CL: Fix querying default device if non exists

Bug: angleproject:5992
Change-Id: Ie43f905fbb9cf41b0f6f88b2db27ebe9de9c37e8
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2906993
Commit-Queue: John Plate <jplate@google.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Cody Northrop <cnorthrop@google.com>
diff --git a/src/libANGLE/CLDevice.cpp b/src/libANGLE/CLDevice.cpp
index 5213d30..1314152 100644
--- a/src/libANGLE/CLDevice.cpp
+++ b/src/libANGLE/CLDevice.cpp
@@ -130,7 +130,6 @@
             break;
 
         // Handle all cl_ulong and aliased types
-        case DeviceInfo::Type:
         case DeviceInfo::MaxMemAllocSize:
         case DeviceInfo::SingleFpConfig:
         case DeviceInfo::DoubleFpConfig:
@@ -193,6 +192,10 @@
             break;
 
         // Handle all cached values
+        case DeviceInfo::Type:
+            copyValue = &mInfo.mType;
+            copySize  = sizeof(mInfo.mType);
+            break;
         case DeviceInfo::MaxWorkItemDimensions:
             valUInt   = static_cast<cl_uint>(mInfo.mMaxWorkItemSizes.size());
             copyValue = &valUInt;
@@ -347,9 +350,10 @@
 
 DevicePtr Device::CreateDevice(Platform &platform,
                                DeviceRefPtr &&parent,
+                               cl_device_type type,
                                const CreateImplFunc &createImplFunc)
 {
-    DevicePtr device(new Device(platform, std::move(parent), createImplFunc));
+    DevicePtr device(new Device(platform, std::move(parent), type, createImplFunc));
     return device->mInfo.isValid() ? std::move(device) : DevicePtr{};
 }
 
@@ -361,12 +365,15 @@
            }) != platforms.cend();
 }
 
-Device::Device(Platform &platform, DeviceRefPtr &&parent, const CreateImplFunc &createImplFunc)
+Device::Device(Platform &platform,
+               DeviceRefPtr &&parent,
+               cl_device_type type,
+               const CreateImplFunc &createImplFunc)
     : _cl_device_id(platform.getDispatch()),
       mPlatform(platform),
       mParent(std::move(parent)),
       mImpl(createImplFunc(*this)),
-      mInfo(mImpl->createInfo())
+      mInfo(mImpl->createInfo(type))
 {}
 
 void Device::destroySubDevice(Device *device)
diff --git a/src/libANGLE/CLDevice.h b/src/libANGLE/CLDevice.h
index bb32d0a..829afe3 100644
--- a/src/libANGLE/CLDevice.h
+++ b/src/libANGLE/CLDevice.h
@@ -49,13 +49,17 @@
 
     static DevicePtr CreateDevice(Platform &platform,
                                   DeviceRefPtr &&parent,
+                                  cl_device_type type,
                                   const CreateImplFunc &createImplFunc);
 
     static bool IsValid(const _cl_device_id *device);
     static bool IsValidType(cl_device_type type);
 
   private:
-    Device(Platform &platform, DeviceRefPtr &&parent, const CreateImplFunc &createImplFunc);
+    Device(Platform &platform,
+           DeviceRefPtr &&parent,
+           cl_device_type type,
+           const CreateImplFunc &createImplFunc);
 
     void destroySubDevice(Device *device);
 
diff --git a/src/libANGLE/CLPlatform.cpp b/src/libANGLE/CLPlatform.cpp
index 527180c..7432b0c 100644
--- a/src/libANGLE/CLPlatform.cpp
+++ b/src/libANGLE/CLPlatform.cpp
@@ -150,9 +150,7 @@
     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 (IsDeviceTypeMatch(deviceType, device->getInfo().mType))
         {
             if (devices != nullptr && found < numEntries)
             {
diff --git a/src/libANGLE/renderer/CLDeviceImpl.cpp b/src/libANGLE/renderer/CLDeviceImpl.cpp
index 1c1efa1..90d28e3 100644
--- a/src/libANGLE/renderer/CLDeviceImpl.cpp
+++ b/src/libANGLE/renderer/CLDeviceImpl.cpp
@@ -14,6 +14,8 @@
 
 CLDeviceImpl::Info::Info() = default;
 
+CLDeviceImpl::Info::Info(cl_device_type type) : mType(type) {}
+
 CLDeviceImpl::Info::~Info() = default;
 
 CLDeviceImpl::Info::Info(Info &&) = default;
diff --git a/src/libANGLE/renderer/CLDeviceImpl.h b/src/libANGLE/renderer/CLDeviceImpl.h
index c0eb8c1..83f4a26 100644
--- a/src/libANGLE/renderer/CLDeviceImpl.h
+++ b/src/libANGLE/renderer/CLDeviceImpl.h
@@ -21,6 +21,7 @@
     struct Info
     {
         Info();
+        explicit Info(cl_device_type type);
         ~Info();
 
         Info(const Info &) = delete;
@@ -29,9 +30,10 @@
         Info(Info &&);
         Info &operator=(Info &&);
 
-        bool isValid() const { return mVersion != 0u; }
+        bool isValid() const { return mType != 0u; }
 
-        cl_version mVersion = 0u;
+        cl_device_type mType = 0u;
+        cl_version mVersion  = 0u;
         std::vector<size_t> mMaxWorkItemSizes;
         NameVersionVector mILsWithVersion;
         NameVersionVector mBuiltInKernelsWithVersion;
@@ -46,7 +48,7 @@
     CLDeviceImpl(const cl::Device &device);
     virtual ~CLDeviceImpl();
 
-    virtual Info createInfo() const = 0;
+    virtual Info createInfo(cl_device_type type) const = 0;
 
     virtual cl_int getInfoUInt(cl::DeviceInfo name, cl_uint *value) const             = 0;
     virtual cl_int getInfoULong(cl::DeviceInfo name, cl_ulong *value) const           = 0;
diff --git a/src/libANGLE/renderer/cl/CLDeviceCL.cpp b/src/libANGLE/renderer/cl/CLDeviceCL.cpp
index 8c06e23..39a95a7 100644
--- a/src/libANGLE/renderer/cl/CLDeviceCL.cpp
+++ b/src/libANGLE/renderer/cl/CLDeviceCL.cpp
@@ -52,9 +52,9 @@
     }
 }
 
-CLDeviceImpl::Info CLDeviceCL::createInfo() const
+CLDeviceImpl::Info CLDeviceCL::createInfo(cl_device_type type) const
 {
-    Info info;
+    Info info(type);
 
     std::vector<char> valString;
     if (!GetDeviceInfo(mNative, cl::DeviceInfo::Version, valString))
@@ -165,7 +165,8 @@
                 return Ptr(new CLDeviceCL(device, nativeSubDevice));
             };
             subDeviceList.emplace_back(cl::Device::CreateDevice(
-                device.getPlatform(), cl::DeviceRefPtr(&device), createImplFunc));
+                device.getPlatform(), cl::DeviceRefPtr(&device),
+                (device.getInfo().mType & ~CL_DEVICE_TYPE_DEFAULT), createImplFunc));
             if (!subDeviceList.back())
             {
                 subDeviceList.clear();
diff --git a/src/libANGLE/renderer/cl/CLDeviceCL.h b/src/libANGLE/renderer/cl/CLDeviceCL.h
index c29a332..9e64040 100644
--- a/src/libANGLE/renderer/cl/CLDeviceCL.h
+++ b/src/libANGLE/renderer/cl/CLDeviceCL.h
@@ -22,7 +22,7 @@
 
     cl_device_id getNative();
 
-    Info createInfo() const override;
+    Info createInfo(cl_device_type type) const override;
 
     cl_int getInfoUInt(cl::DeviceInfo name, cl_uint *value) const override;
     cl_int getInfoULong(cl::DeviceInfo name, cl_ulong *value) const override;
diff --git a/src/libANGLE/renderer/cl/CLPlatformCL.cpp b/src/libANGLE/renderer/cl/CLPlatformCL.cpp
index 634caa3..3c08093 100644
--- a/src/libANGLE/renderer/cl/CLPlatformCL.cpp
+++ b/src/libANGLE/renderer/cl/CLPlatformCL.cpp
@@ -313,12 +313,46 @@
         if (mNative->getDispatch().clGetDeviceIDs(mNative, CL_DEVICE_TYPE_ALL, numDevices,
                                                   nativeDevices.data(), nullptr) == CL_SUCCESS)
         {
-            for (cl_device_id nativeDevice : nativeDevices)
+            // Fetch all device types for front end initialization, and find the default device.
+            // If none exists declare first device as default.
+            std::vector<cl_device_type> types(nativeDevices.size(), 0u);
+            size_t defaultIndex = 0u;
+            for (size_t index = 0u; index < nativeDevices.size(); ++index)
             {
+                if (nativeDevices[index]->getDispatch().clGetDeviceInfo(
+                        nativeDevices[index], CL_DEVICE_TYPE, sizeof(cl_device_type), &types[index],
+                        nullptr) == CL_SUCCESS)
+                {
+                    // If default device found, select it
+                    if ((types[index] & CL_DEVICE_TYPE_DEFAULT) != 0u)
+                    {
+                        defaultIndex = index;
+                    }
+                }
+                else
+                {
+                    types.clear();
+                    nativeDevices.clear();
+                }
+            }
+
+            for (size_t index = 0u; index < nativeDevices.size(); ++index)
+            {
+                // Make sure the default bit is set in exactly one device
+                if (index == defaultIndex)
+                {
+                    types[index] |= CL_DEVICE_TYPE_DEFAULT;
+                }
+                else
+                {
+                    types[index] &= ~CL_DEVICE_TYPE_DEFAULT;
+                }
+
                 const cl::Device::CreateImplFunc createImplFunc = [&](const cl::Device &device) {
-                    return CLDeviceCL::Ptr(new CLDeviceCL(device, nativeDevice));
+                    return CLDeviceCL::Ptr(new CLDeviceCL(device, nativeDevices[index]));
                 };
-                devices.emplace_back(cl::Device::CreateDevice(platform, nullptr, createImplFunc));
+                devices.emplace_back(
+                    cl::Device::CreateDevice(platform, nullptr, types[index], createImplFunc));
                 if (!devices.back())
                 {
                     devices.clear();
@@ -393,8 +427,9 @@
     }
 
     // The absolute path to ANGLE's OpenCL library is needed and it is assumed here that
-    // it is in the same directory as the executable which contains this CL back end.
-    std::string libPath = angle::GetExecutableDirectory();
+    // it is in the same directory as the module which contains this CL back end.
+    // TODO(http://anglebug.com/5949) Use GetModuleDirectory when it relands
+    std::string libPath;  // = angle::GetModuleDirectory();
     if (!libPath.empty() && libPath.back() != angle::GetPathSeparator())
     {
         libPath += angle::GetPathSeparator();
diff --git a/src/libANGLE/renderer/vulkan/CLDeviceVk.cpp b/src/libANGLE/renderer/vulkan/CLDeviceVk.cpp
index 3ac2570..e86f6cb 100644
--- a/src/libANGLE/renderer/vulkan/CLDeviceVk.cpp
+++ b/src/libANGLE/renderer/vulkan/CLDeviceVk.cpp
@@ -16,9 +16,9 @@
 
 CLDeviceVk::~CLDeviceVk() = default;
 
-CLDeviceImpl::Info CLDeviceVk::createInfo() const
+CLDeviceImpl::Info CLDeviceVk::createInfo(cl_device_type type) const
 {
-    CLDeviceImpl::Info info;
+    Info info(type);
     return info;
 }
 
diff --git a/src/libANGLE/renderer/vulkan/CLDeviceVk.h b/src/libANGLE/renderer/vulkan/CLDeviceVk.h
index 1d42efc..f511d11 100644
--- a/src/libANGLE/renderer/vulkan/CLDeviceVk.h
+++ b/src/libANGLE/renderer/vulkan/CLDeviceVk.h
@@ -21,7 +21,7 @@
     explicit CLDeviceVk(const cl::Device &device);
     ~CLDeviceVk() override;
 
-    Info createInfo() const override;
+    Info createInfo(cl_device_type type) const override;
 
     cl_int getInfoUInt(cl::DeviceInfo name, cl_uint *value) const override;
     cl_int getInfoULong(cl::DeviceInfo name, cl_ulong *value) const override;
diff --git a/src/libANGLE/renderer/vulkan/CLPlatformVk.cpp b/src/libANGLE/renderer/vulkan/CLPlatformVk.cpp
index 5318eda..970570b 100644
--- a/src/libANGLE/renderer/vulkan/CLPlatformVk.cpp
+++ b/src/libANGLE/renderer/vulkan/CLPlatformVk.cpp
@@ -58,11 +58,12 @@
 
 cl::DevicePtrList CLPlatformVk::createDevices(cl::Platform &platform) const
 {
+    cl_device_type type = 0u;  // TODO(jplate) Fetch device type from Vulkan
     cl::DevicePtrList devices;
     const cl::Device::CreateImplFunc createImplFunc = [](const cl::Device &device) {
         return CLDeviceVk::Ptr(new CLDeviceVk(device));
     };
-    devices.emplace_back(cl::Device::CreateDevice(platform, nullptr, createImplFunc));
+    devices.emplace_back(cl::Device::CreateDevice(platform, nullptr, type, createImplFunc));
     if (!devices.back())
     {
         devices.clear();