blob: 7f98ccfa66f61d36426ec47a594afe966426e558 [file] [log] [blame]
//
// 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