Edit

kc3-lang/angle/src/libANGLE/CLDevice.cpp

Branch :

  • Show log

    Commit

  • Author : John Plate
    Date : 2021-06-17 09:29:29
    Hash : 44a5c913
    Message : CL: Make CL front end and back end thread-safe Add locking to all mutable variables of the CL objects in the front end and pass-through back end to make them thread-safe. This fixes a crash in a multi-threaded CTS test. Bug: angleproject:6015 Change-Id: I1d6471c851217639411c434c82acd32d14035291 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2967468 Commit-Queue: John Plate <jplate@google.com> Reviewed-by: Cody Northrop <cnorthrop@google.com> Reviewed-by: Jamie Madill <jmadill@chromium.org>

  • src/libANGLE/CLDevice.cpp
  • //
    // 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.
    //
    // CLDevice.cpp: Implements the cl::Device class.
    
    #include "libANGLE/CLDevice.h"
    
    #include "libANGLE/CLPlatform.h"
    
    #include "common/string_utils.h"
    
    #include <cstring>
    
    namespace cl
    {
    
    cl_int Device::getInfo(DeviceInfo name, size_t valueSize, void *value, size_t *valueSizeRet) const
    {
        static_assert(std::is_same<cl_uint, cl_bool>::value &&
                          std::is_same<cl_uint, cl_device_mem_cache_type>::value &&
                          std::is_same<cl_uint, cl_device_local_mem_type>::value &&
                          std::is_same<cl_uint, cl_version>::value &&
                          std::is_same<cl_ulong, cl_device_type>::value &&
                          std::is_same<cl_ulong, cl_device_fp_config>::value &&
                          std::is_same<cl_ulong, cl_device_exec_capabilities>::value &&
                          std::is_same<cl_ulong, cl_command_queue_properties>::value &&
                          std::is_same<cl_ulong, cl_device_affinity_domain>::value &&
                          std::is_same<cl_ulong, cl_device_svm_capabilities>::value &&
                          std::is_same<cl_ulong, cl_device_atomic_capabilities>::value &&
                          std::is_same<cl_ulong, cl_device_device_enqueue_capabilities>::value,
                      "OpenCL type mismatch");
    
        cl_uint valUInt   = 0u;
        cl_ulong valULong = 0u;
        size_t valSizeT   = 0u;
        void *valPointer  = nullptr;
        std::vector<char> valString;
    
        const void *copyValue = nullptr;
        size_t copySize       = 0u;
        cl_int result         = CL_SUCCESS;
    
        // The info names are sorted within their type group in the order they appear in the OpenCL
        // specification, so it is easier to compare them side-by-side when looking for changes.
        // https://www.khronos.org/registry/OpenCL/specs/3.0-unified/html/OpenCL_API.html#clGetDeviceInfo
        switch (name)
        {
            // Handle all cl_uint and aliased types
            case DeviceInfo::VendorID:
            case DeviceInfo::MaxComputeUnits:
            case DeviceInfo::PreferredVectorWidthChar:
            case DeviceInfo::PreferredVectorWidthShort:
            case DeviceInfo::PreferredVectorWidthInt:
            case DeviceInfo::PreferredVectorWidthLong:
            case DeviceInfo::PreferredVectorWidthFloat:
            case DeviceInfo::PreferredVectorWidthDouble:
            case DeviceInfo::PreferredVectorWidthHalf:
            case DeviceInfo::NativeVectorWidthChar:
            case DeviceInfo::NativeVectorWidthShort:
            case DeviceInfo::NativeVectorWidthInt:
            case DeviceInfo::NativeVectorWidthLong:
            case DeviceInfo::NativeVectorWidthFloat:
            case DeviceInfo::NativeVectorWidthDouble:
            case DeviceInfo::NativeVectorWidthHalf:
            case DeviceInfo::MaxClockFrequency:
            case DeviceInfo::AddressBits:
            case DeviceInfo::MaxReadImageArgs:
            case DeviceInfo::MaxWriteImageArgs:
            case DeviceInfo::MaxReadWriteImageArgs:
            case DeviceInfo::MaxSamplers:
            case DeviceInfo::MaxPipeArgs:
            case DeviceInfo::PipeMaxActiveReservations:
            case DeviceInfo::PipeMaxPacketSize:
            case DeviceInfo::MinDataTypeAlignSize:
            case DeviceInfo::GlobalMemCacheType:
            case DeviceInfo::GlobalMemCachelineSize:
            case DeviceInfo::MaxConstantArgs:
            case DeviceInfo::LocalMemType:
            case DeviceInfo::ErrorCorrectionSupport:
            case DeviceInfo::HostUnifiedMemory:
            case DeviceInfo::EndianLittle:
            case DeviceInfo::Available:
            case DeviceInfo::CompilerAvailable:
            case DeviceInfo::LinkerAvailable:
            case DeviceInfo::QueueOnDevicePreferredSize:
            case DeviceInfo::MaxOnDeviceQueues:
            case DeviceInfo::MaxOnDeviceEvents:
            case DeviceInfo::PreferredInteropUserSync:
            case DeviceInfo::PartitionMaxSubDevices:
            case DeviceInfo::PreferredPlatformAtomicAlignment:
            case DeviceInfo::PreferredGlobalAtomicAlignment:
            case DeviceInfo::PreferredLocalAtomicAlignment:
            case DeviceInfo::MaxNumSubGroups:
            case DeviceInfo::SubGroupIndependentForwardProgress:
            case DeviceInfo::NonUniformWorkGroupSupport:
            case DeviceInfo::WorkGroupCollectiveFunctionsSupport:
            case DeviceInfo::GenericAddressSpaceSupport:
            case DeviceInfo::PipeSupport:
                result    = mImpl->getInfoUInt(name, &valUInt);
                copyValue = &valUInt;
                copySize  = sizeof(valUInt);
                break;
    
            // Handle all cl_ulong and aliased types
            case DeviceInfo::SingleFpConfig:
            case DeviceInfo::DoubleFpConfig:
            case DeviceInfo::GlobalMemCacheSize:
            case DeviceInfo::GlobalMemSize:
            case DeviceInfo::MaxConstantBufferSize:
            case DeviceInfo::LocalMemSize:
            case DeviceInfo::QueueOnHostProperties:
            case DeviceInfo::QueueOnDeviceProperties:
            case DeviceInfo::PartitionAffinityDomain:
            case DeviceInfo::SVM_Capabilities:
            case DeviceInfo::AtomicMemoryCapabilities:
            case DeviceInfo::AtomicFenceCapabilities:
            case DeviceInfo::DeviceEnqueueCapabilities:
            case DeviceInfo::HalfFpConfig:
                result    = mImpl->getInfoULong(name, &valULong);
                copyValue = &valULong;
                copySize  = sizeof(valULong);
                break;
    
            // Handle all size_t and aliased types
            case DeviceInfo::MaxWorkGroupSize:
            case DeviceInfo::MaxParameterSize:
            case DeviceInfo::MaxGlobalVariableSize:
            case DeviceInfo::GlobalVariablePreferredTotalSize:
            case DeviceInfo::ProfilingTimerResolution:
            case DeviceInfo::PrintfBufferSize:
            case DeviceInfo::PreferredWorkGroupSizeMultiple:
                result    = mImpl->getInfoSizeT(name, &valSizeT);
                copyValue = &valSizeT;
                copySize  = sizeof(valSizeT);
                break;
    
            // Handle all string types
            case DeviceInfo::Name:
            case DeviceInfo::Vendor:
            case DeviceInfo::DriverVersion:
            case DeviceInfo::Profile:
            case DeviceInfo::OpenCL_C_Version:
            case DeviceInfo::LatestConformanceVersionPassed:
                result = mImpl->getInfoStringLength(name, &copySize);
                if (result != CL_SUCCESS)
                {
                    return result;
                }
                valString.resize(copySize, '\0');
                result    = mImpl->getInfoString(name, copySize, valString.data());
                copyValue = valString.data();
                break;
    
            // Handle all cached values
            case DeviceInfo::Type:
                copyValue = &mInfo.type;
                copySize  = sizeof(mInfo.type);
                break;
            case DeviceInfo::MaxWorkItemDimensions:
                valUInt   = static_cast<cl_uint>(mInfo.maxWorkItemSizes.size());
                copyValue = &valUInt;
                copySize  = sizeof(valUInt);
                break;
            case DeviceInfo::MaxWorkItemSizes:
                copyValue = mInfo.maxWorkItemSizes.data();
                copySize  = mInfo.maxWorkItemSizes.size() *
                           sizeof(decltype(mInfo.maxWorkItemSizes)::value_type);
                break;
            case DeviceInfo::MaxMemAllocSize:
                copyValue = &mInfo.maxMemAllocSize;
                copySize  = sizeof(mInfo.maxMemAllocSize);
                break;
            case DeviceInfo::ImageSupport:
                copyValue = &mInfo.imageSupport;
                copySize  = sizeof(mInfo.imageSupport);
                break;
            case DeviceInfo::IL_Version:
                copyValue = mInfo.IL_Version.c_str();
                copySize  = mInfo.IL_Version.length() + 1u;
                break;
            case DeviceInfo::ILsWithVersion:
                copyValue = mInfo.ILsWithVersion.data();
                copySize =
                    mInfo.ILsWithVersion.size() * sizeof(decltype(mInfo.ILsWithVersion)::value_type);
                break;
            case DeviceInfo::Image2D_MaxWidth:
                copyValue = &mInfo.image2D_MaxWidth;
                copySize  = sizeof(mInfo.image2D_MaxWidth);
                break;
            case DeviceInfo::Image2D_MaxHeight:
                copyValue = &mInfo.image2D_MaxHeight;
                copySize  = sizeof(mInfo.image2D_MaxHeight);
                break;
            case DeviceInfo::Image3D_MaxWidth:
                copyValue = &mInfo.image3D_MaxWidth;
                copySize  = sizeof(mInfo.image3D_MaxWidth);
                break;
            case DeviceInfo::Image3D_MaxHeight:
                copyValue = &mInfo.image3D_MaxHeight;
                copySize  = sizeof(mInfo.image3D_MaxHeight);
                break;
            case DeviceInfo::Image3D_MaxDepth:
                copyValue = &mInfo.image3D_MaxDepth;
                copySize  = sizeof(mInfo.image3D_MaxDepth);
                break;
            case DeviceInfo::ImageMaxBufferSize:
                copyValue = &mInfo.imageMaxBufferSize;
                copySize  = sizeof(mInfo.imageMaxBufferSize);
                break;
            case DeviceInfo::ImageMaxArraySize:
                copyValue = &mInfo.imageMaxArraySize;
                copySize  = sizeof(mInfo.imageMaxArraySize);
                break;
            case DeviceInfo::ImagePitchAlignment:
                copyValue = &mInfo.imagePitchAlignment;
                copySize  = sizeof(mInfo.imagePitchAlignment);
                break;
            case DeviceInfo::ImageBaseAddressAlignment:
                copyValue = &mInfo.imageBaseAddressAlignment;
                copySize  = sizeof(mInfo.imageBaseAddressAlignment);
                break;
            case DeviceInfo::MemBaseAddrAlign:
                copyValue = &mInfo.memBaseAddrAlign;
                copySize  = sizeof(mInfo.memBaseAddrAlign);
                break;
            case DeviceInfo::ExecutionCapabilities:
                copyValue = &mInfo.execCapabilities;
                copySize  = sizeof(mInfo.execCapabilities);
                break;
            case DeviceInfo::QueueOnDeviceMaxSize:
                copyValue = &mInfo.queueOnDeviceMaxSize;
                copySize  = sizeof(mInfo.queueOnDeviceMaxSize);
                break;
            case DeviceInfo::BuiltInKernels:
                copyValue = mInfo.builtInKernels.c_str();
                copySize  = mInfo.builtInKernels.length() + 1u;
                break;
            case DeviceInfo::BuiltInKernelsWithVersion:
                copyValue = mInfo.builtInKernelsWithVersion.data();
                copySize  = mInfo.builtInKernelsWithVersion.size() *
                           sizeof(decltype(mInfo.builtInKernelsWithVersion)::value_type);
                break;
            case DeviceInfo::Version:
                copyValue = mInfo.versionStr.c_str();
                copySize  = mInfo.versionStr.length() + 1u;
                break;
            case DeviceInfo::NumericVersion:
                copyValue = &mInfo.version;
                copySize  = sizeof(mInfo.version);
                break;
            case DeviceInfo::OpenCL_C_AllVersions:
                copyValue = mInfo.OpenCL_C_AllVersions.data();
                copySize  = mInfo.OpenCL_C_AllVersions.size() *
                           sizeof(decltype(mInfo.OpenCL_C_AllVersions)::value_type);
                break;
            case DeviceInfo::OpenCL_C_Features:
                copyValue = mInfo.OpenCL_C_Features.data();
                copySize  = mInfo.OpenCL_C_Features.size() *
                           sizeof(decltype(mInfo.OpenCL_C_Features)::value_type);
                break;
            case DeviceInfo::Extensions:
                copyValue = mInfo.extensions.c_str();
                copySize  = mInfo.extensions.length() + 1u;
                break;
            case DeviceInfo::ExtensionsWithVersion:
                copyValue = mInfo.extensionsWithVersion.data();
                copySize  = mInfo.extensionsWithVersion.size() *
                           sizeof(decltype(mInfo.extensionsWithVersion)::value_type);
                break;
            case DeviceInfo::PartitionProperties:
                copyValue = mInfo.partitionProperties.data();
                copySize  = mInfo.partitionProperties.size() *
                           sizeof(decltype(mInfo.partitionProperties)::value_type);
                break;
            case DeviceInfo::PartitionType:
                copyValue = mInfo.partitionType.data();
                copySize =
                    mInfo.partitionType.size() * sizeof(decltype(mInfo.partitionType)::value_type);
                break;
    
            // Handle all mapped values
            case DeviceInfo::Platform:
                valPointer = mPlatform.getNative();
                copyValue  = &valPointer;
                copySize   = sizeof(valPointer);
                break;
            case DeviceInfo::ParentDevice:
                valPointer = Device::CastNative(mParent.get());
                copyValue  = &valPointer;
                copySize   = sizeof(valPointer);
                break;
            case DeviceInfo::ReferenceCount:
                valUInt   = isRoot() ? 1u : getRefCount();
                copyValue = &valUInt;
                copySize  = sizeof(valUInt);
                break;
    
            default:
                ASSERT(false);
                return CL_INVALID_VALUE;
        }
    
        if (result != CL_SUCCESS)
        {
            return result;
        }
        if (value != nullptr)
        {
            // CL_INVALID_VALUE if size in bytes specified by param_value_size is < size of return
            // type as specified in the Device 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 Device::createSubDevices(const cl_device_partition_property *properties,
                                    cl_uint numDevices,
                                    cl_device_id *subDevices,
                                    cl_uint *numDevicesRet)
    {
        if (subDevices == nullptr)
        {
            numDevices = 0u;
        }
        rx::CLDeviceImpl::CreateFuncs subDeviceCreateFuncs;
        const cl_int errorCode =
            mImpl->createSubDevices(properties, numDevices, subDeviceCreateFuncs, numDevicesRet);
        if (errorCode == CL_SUCCESS)
        {
            cl::DeviceType type = mInfo.type;
            type.clear(CL_DEVICE_TYPE_DEFAULT);
            DevicePtrs devices;
            devices.reserve(subDeviceCreateFuncs.size());
            while (!subDeviceCreateFuncs.empty())
            {
                devices.emplace_back(new Device(mPlatform, this, type, subDeviceCreateFuncs.front()));
                // Release initialization reference, lifetime controlled by RefPointer.
                devices.back()->release();
                if (!devices.back()->mInfo.isValid())
                {
                    return CL_INVALID_VALUE;
                }
                subDeviceCreateFuncs.pop_front();
            }
            for (DevicePtr &subDevice : devices)
            {
                *subDevices++ = subDevice.release();
            }
        }
        return errorCode;
    }
    
    Device::~Device() = default;
    
    bool Device::supportsBuiltInKernel(const std::string &name) const
    {
        return angle::ContainsToken(mInfo.builtInKernels, ';', name);
    }
    
    bool Device::supportsNativeImageDimensions(const cl_image_desc &desc) const
    {
        switch (FromCLenum<MemObjectType>(desc.image_type))
        {
            case MemObjectType::Image1D:
                return desc.image_width <= mInfo.image2D_MaxWidth;
            case MemObjectType::Image2D:
                return desc.image_width <= mInfo.image2D_MaxWidth &&
                       desc.image_height <= mInfo.image2D_MaxHeight;
            case MemObjectType::Image3D:
                return desc.image_width <= mInfo.image3D_MaxWidth &&
                       desc.image_height <= mInfo.image3D_MaxHeight &&
                       desc.image_depth <= mInfo.image3D_MaxDepth;
            case MemObjectType::Image1D_Array:
                return desc.image_width <= mInfo.image2D_MaxWidth &&
                       desc.image_array_size <= mInfo.imageMaxArraySize;
            case MemObjectType::Image2D_Array:
                return desc.image_width <= mInfo.image2D_MaxWidth &&
                       desc.image_height <= mInfo.image2D_MaxHeight &&
                       desc.image_array_size <= mInfo.imageMaxArraySize;
            case MemObjectType::Image1D_Buffer:
                return desc.image_width <= mInfo.imageMaxBufferSize;
            default:
                ASSERT(false);
                break;
        }
        return false;
    }
    
    bool Device::supportsImageDimensions(const ImageDescriptor &desc) const
    {
        switch (desc.type)
        {
            case MemObjectType::Image1D:
                return desc.width <= mInfo.image2D_MaxWidth;
            case MemObjectType::Image2D:
                return desc.width <= mInfo.image2D_MaxWidth && desc.height <= mInfo.image2D_MaxHeight;
            case MemObjectType::Image3D:
                return desc.width <= mInfo.image3D_MaxWidth && desc.height <= mInfo.image3D_MaxHeight &&
                       desc.depth <= mInfo.image3D_MaxDepth;
            case MemObjectType::Image1D_Array:
                return desc.width <= mInfo.image2D_MaxWidth &&
                       desc.arraySize <= mInfo.imageMaxArraySize;
            case MemObjectType::Image2D_Array:
                return desc.width <= mInfo.image2D_MaxWidth && desc.height <= mInfo.image2D_MaxHeight &&
                       desc.arraySize <= mInfo.imageMaxArraySize;
            case MemObjectType::Image1D_Buffer:
                return desc.width <= mInfo.imageMaxBufferSize;
            default:
                ASSERT(false);
                break;
        }
        return false;
    }
    
    Device::Device(Platform &platform,
                   Device *parent,
                   DeviceType type,
                   const rx::CLDeviceImpl::CreateFunc &createFunc)
        : mPlatform(platform), mParent(parent), mImpl(createFunc(*this)), mInfo(mImpl->createInfo(type))
    {}
    
    }  // namespace cl