| // |
| // 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 "libANGLE/CLContext.h" |
| #include "libANGLE/CLDevice.h" |
| |
| #include <cstring> |
| |
| namespace cl |
| { |
| |
| namespace |
| { |
| |
| bool IsDeviceTypeMatch(DeviceType select, DeviceType type) |
| { |
| // The type 'DeviceType' is a bitfield, so it matches if any selected bit is set. |
| // A custom device is an exception, which only matches if it was explicitely selected, see: |
| // 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.isSet(select); |
| } |
| |
| 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<cl_platform_id>(*propIt++)->cast<Platform>(); |
| 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 |
| |
| void Platform::Initialize(const cl_icd_dispatch &dispatch, |
| rx::CLPlatformImpl::CreateFuncs &&createFuncs) |
| { |
| PlatformPtrs &platforms = GetPointers(); |
| ASSERT(_cl_platform_id::sDispatch == nullptr && platforms.empty()); |
| if (_cl_platform_id::sDispatch != nullptr || !platforms.empty()) |
| { |
| ERR() << "Already initialized"; |
| return; |
| } |
| Dispatch::sDispatch = &dispatch; |
| |
| platforms.reserve(createFuncs.size()); |
| while (!createFuncs.empty()) |
| { |
| platforms.emplace_back(new Platform(createFuncs.front())); |
| // Release initialization reference, lifetime controlled by RefPointer. |
| platforms.back()->release(); |
| if (!platforms.back()->mInfo.isValid() || platforms.back()->mDevices.empty()) |
| { |
| platforms.pop_back(); |
| } |
| createFuncs.pop_front(); |
| } |
| } |
| |
| cl_int Platform::GetPlatformIDs(cl_uint numEntries, |
| cl_platform_id *platforms, |
| cl_uint *numPlatforms) |
| { |
| const PlatformPtrs &availPlatforms = GetPlatforms(); |
| if (numPlatforms != nullptr) |
| { |
| *numPlatforms = static_cast<cl_uint>(availPlatforms.size()); |
| } |
| if (platforms != nullptr) |
| { |
| cl_uint entry = 0u; |
| auto platformIt = availPlatforms.cbegin(); |
| while (entry < numEntries && platformIt != availPlatforms.cend()) |
| { |
| platforms[entry++] = (*platformIt++).get(); |
| } |
| } |
| return CL_SUCCESS; |
| } |
| |
| cl_int Platform::getInfo(PlatformInfo name, |
| size_t valueSize, |
| void *value, |
| size_t *valueSizeRet) const |
| { |
| const void *copyValue = nullptr; |
| size_t copySize = 0u; |
| |
| switch (name) |
| { |
| case PlatformInfo::Profile: |
| copyValue = mInfo.profile.c_str(); |
| copySize = mInfo.profile.length() + 1u; |
| break; |
| case PlatformInfo::Version: |
| copyValue = mInfo.versionStr.c_str(); |
| copySize = mInfo.versionStr.length() + 1u; |
| break; |
| case PlatformInfo::NumericVersion: |
| copyValue = &mInfo.version; |
| copySize = sizeof(mInfo.version); |
| break; |
| case PlatformInfo::Name: |
| copyValue = mInfo.name.c_str(); |
| copySize = mInfo.name.length() + 1u; |
| break; |
| case PlatformInfo::Vendor: |
| copyValue = kVendor; |
| copySize = sizeof(kVendor); |
| break; |
| case PlatformInfo::Extensions: |
| copyValue = mInfo.extensions.c_str(); |
| copySize = mInfo.extensions.length() + 1u; |
| break; |
| case PlatformInfo::ExtensionsWithVersion: |
| copyValue = mInfo.extensionsWithVersion.data(); |
| copySize = mInfo.extensionsWithVersion.size() * |
| sizeof(decltype(mInfo.extensionsWithVersion)::value_type); |
| break; |
| case PlatformInfo::HostTimerResolution: |
| copyValue = &mInfo.hostTimerRes; |
| copySize = sizeof(mInfo.hostTimerRes); |
| break; |
| case PlatformInfo::IcdSuffix: |
| copyValue = kIcdSuffix; |
| copySize = sizeof(kIcdSuffix); |
| break; |
| default: |
| ASSERT(false); |
| return CL_INVALID_VALUE; |
| } |
| |
| if (value != nullptr) |
| { |
| // CL_INVALID_VALUE if size in bytes specified by param_value_size is < size of return type |
| // as specified in the OpenCL Platform Queries table, and param_value is not a NULL value. |
| 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(DeviceType deviceType, |
| cl_uint numEntries, |
| cl_device_id *devices, |
| cl_uint *numDevices) const |
| { |
| cl_uint found = 0u; |
| for (const DevicePtr &device : mDevices) |
| { |
| if (IsDeviceTypeMatch(deviceType, device->getInfo().type)) |
| { |
| if (devices != nullptr && found < numEntries) |
| { |
| devices[found] = device.get(); |
| } |
| ++found; |
| } |
| } |
| if (numDevices != nullptr) |
| { |
| *numDevices = found; |
| } |
| |
| // CL_DEVICE_NOT_FOUND if no OpenCL devices that matched device_type were found. |
| if (found == 0u) |
| { |
| return CL_DEVICE_NOT_FOUND; |
| } |
| |
| 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 &errorCode) |
| { |
| Platform *platform = nullptr; |
| bool userSync = false; |
| Context::PropArray propArray = ParseContextProperties(properties, platform, userSync); |
| ASSERT(platform != nullptr); |
| DevicePtrs devs; |
| devs.reserve(numDevices); |
| while (numDevices-- != 0u) |
| { |
| devs.emplace_back(&(*devices++)->cast<Device>()); |
| } |
| return Object::Create<Context>(errorCode, *platform, std::move(propArray), std::move(devs), |
| notify, userData, userSync); |
| } |
| |
| cl_context Platform::CreateContextFromType(const cl_context_properties *properties, |
| DeviceType deviceType, |
| ContextErrorCB notify, |
| void *userData, |
| cl_int &errorCode) |
| { |
| Platform *platform = nullptr; |
| bool userSync = false; |
| Context::PropArray propArray = ParseContextProperties(properties, platform, userSync); |
| ASSERT(platform != nullptr); |
| return Object::Create<Context>(errorCode, *platform, std::move(propArray), deviceType, notify, |
| userData, userSync); |
| } |
| |
| cl_int Platform::unloadCompiler() |
| { |
| return mImpl->unloadCompiler(); |
| } |
| |
| Platform::~Platform() = default; |
| |
| Platform::Platform(const rx::CLPlatformImpl::CreateFunc &createFunc) |
| : mImpl(createFunc(*this)), |
| mInfo(mImpl->createInfo()), |
| mDevices(createDevices(mImpl->createDevices())) |
| {} |
| |
| DevicePtrs Platform::createDevices(rx::CLDeviceImpl::CreateDatas &&createDatas) |
| { |
| DevicePtrs devices; |
| devices.reserve(createDatas.size()); |
| while (!createDatas.empty()) |
| { |
| devices.emplace_back( |
| new Device(*this, nullptr, createDatas.front().first, createDatas.front().second)); |
| // Release initialization reference, lifetime controlled by RefPointer. |
| devices.back()->release(); |
| if (!devices.back()->mInfo.isValid()) |
| { |
| devices.pop_back(); |
| } |
| createDatas.pop_front(); |
| } |
| return devices; |
| } |
| |
| constexpr char Platform::kVendor[]; |
| constexpr char Platform::kIcdSuffix[]; |
| |
| } // namespace cl |