diff --git a/sycl/include/CL/sycl.hpp b/sycl/include/CL/sycl.hpp index 06053b487d0fd..c97b971c53482 100644 --- a/sycl/include/CL/sycl.hpp +++ b/sycl/include/CL/sycl.hpp @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/sycl/include/CL/sycl/backend/opencl.hpp b/sycl/include/CL/sycl/backend/opencl.hpp index 881ef69fbb1dd..e646d9e33ac3b 100644 --- a/sycl/include/CL/sycl/backend/opencl.hpp +++ b/sycl/include/CL/sycl/backend/opencl.hpp @@ -16,10 +16,26 @@ __SYCL_INLINE_NAMESPACE(cl) { namespace sycl { +template <> struct interop { + using type = cl_platform_id; +}; + +template <> struct interop { + using type = cl_device_id; +}; + +template <> struct interop { + using type = cl_context; +}; + template <> struct interop { using type = cl_command_queue; }; +template <> struct interop { + using type = cl_program; +}; + template struct interop::value>::type * = nullptr> +T make(typename interop::type Interop) { + return make_platform(detail::pi::cast(Interop)); +} + +// Construction of SYCL device. +template ::value>::type * = nullptr> +T make(typename interop::type Interop) { + return make_device(detail::pi::cast(Interop)); +} + +// Construction of SYCL context. +template ::value>::type * = nullptr> +T make(typename interop::type Interop) { + return make_context(detail::pi::cast(Interop)); +} + +// Construction of SYCL program. +template ::value>::type * = nullptr> +T make(const context &Context, + typename interop::type Interop) { + return make_program(Context, detail::pi::cast(Interop)); +} + +// Construction of SYCL queue. +template ::value>::type * = nullptr> +T make(const context &Context, + typename interop::type Interop) { + return make_queue(Context, detail::pi::cast(Interop)); +} + +} // namespace opencl } // namespace sycl } // __SYCL_INLINE_NAMESPACE(cl) diff --git a/sycl/include/CL/sycl/detail/pi.def b/sycl/include/CL/sycl/detail/pi.def index 52d4cfdcdff24..6c76358d5576e 100644 --- a/sycl/include/CL/sycl/detail/pi.def +++ b/sycl/include/CL/sycl/detail/pi.def @@ -17,6 +17,8 @@ // Platform _PI_API(piPlatformsGet) _PI_API(piPlatformGetInfo) +_PI_API(piextPlatformGetNativeHandle) +_PI_API(piextPlatformCreateWithNativeHandle) // Device _PI_API(piDevicesGet) _PI_API(piDeviceGetInfo) diff --git a/sycl/include/CL/sycl/detail/pi.h b/sycl/include/CL/sycl/detail/pi.h index 9c35f7f3ec458..6718261c485b8 100644 --- a/sycl/include/CL/sycl/detail/pi.h +++ b/sycl/include/CL/sycl/detail/pi.h @@ -805,6 +805,21 @@ __SYCL_EXPORT pi_result piPlatformGetInfo(pi_platform platform, void *param_value, size_t *param_value_size_ret); +/// Gets the native handle of a PI platform object. +/// +/// \param platform is the PI platform to get the native handle of. +/// \param nativeHandle is the native handle of platform. +__SYCL_EXPORT pi_result piextPlatformGetNativeHandle( + pi_platform platform, pi_native_handle *nativeHandle); + +/// Creates PI platform object from a native handle. +/// NOTE: The created PI object takes ownership of the native handle. +/// +/// \param nativeHandle is the native handle to create PI device from. +/// \param platform is the PI platform created from the native handle. +__SYCL_EXPORT pi_result piextPlatformCreateWithNativeHandle( + pi_native_handle nativeHandle, pi_platform *platform); + __SYCL_EXPORT pi_result piDevicesGet(pi_platform platform, pi_device_type device_type, pi_uint32 num_entries, pi_device *devices, diff --git a/sycl/include/CL/sycl/detail/pi.hpp b/sycl/include/CL/sycl/detail/pi.hpp index aecaf438847be..5ff6e6312df36 100644 --- a/sycl/include/CL/sycl/detail/pi.hpp +++ b/sycl/include/CL/sycl/detail/pi.hpp @@ -139,6 +139,9 @@ extern std::shared_ptr GlobalPlugin; // Performs PI one-time initialization. const vector_class &initialize(); +// Get the plugin serving given backend. +template const plugin &getPlugin(); + // Utility Functions to get Function Name for a PI Api. template struct PiFuncInfo {}; diff --git a/sycl/include/CL/sycl/device.hpp b/sycl/include/CL/sycl/device.hpp index 985613ae7b000..ded25fc724881 100644 --- a/sycl/include/CL/sycl/device.hpp +++ b/sycl/include/CL/sycl/device.hpp @@ -176,8 +176,7 @@ class __SYCL_EXPORT device { /// \return a native handle, the type of which defined by the backend. template auto get_native() const -> typename interop::type { - return static_cast::type>( - getNative()); + return (typename interop::type)getNative(); } private: diff --git a/sycl/include/CL/sycl/platform.hpp b/sycl/include/CL/sycl/platform.hpp index e33ffd3776082..6c9d98fa8af1e 100644 --- a/sycl/include/CL/sycl/platform.hpp +++ b/sycl/include/CL/sycl/platform.hpp @@ -102,7 +102,18 @@ class __SYCL_EXPORT platform { /// \return a vector of all available SYCL platforms. static vector_class get_platforms(); + /// Gets the native handle of the SYCL platform. + /// + /// \return a native handle, the type of which defined by the backend. + template + auto get_native() const -> typename interop::type { + return detail::pi::cast::type>( + getNative()); + } + private: + pi_native_handle getNative() const; + shared_ptr_class impl; platform(shared_ptr_class impl) : impl(impl) {} diff --git a/sycl/include/CL/sycl/queue.hpp b/sycl/include/CL/sycl/queue.hpp index 097a4f761cbfc..77ce1fab86474 100644 --- a/sycl/include/CL/sycl/queue.hpp +++ b/sycl/include/CL/sycl/queue.hpp @@ -703,8 +703,12 @@ class __SYCL_EXPORT queue { pi_native_handle getNative() const; shared_ptr_class impl; + queue(shared_ptr_class impl) : impl(impl) {} + template friend decltype(Obj::impl) detail::getSyclObjImpl(const Obj &SyclObject); + template + friend T detail::createSyclObjFromImpl(decltype(T::impl) ImplObj); /// A template-free version of submit. event submit_impl(function_class CGH, diff --git a/sycl/plugins/level_zero/pi_level0.cpp b/sycl/plugins/level_zero/pi_level0.cpp index 6f118b6b82f0f..c1f571a4ea9d8 100644 --- a/sycl/plugins/level_zero/pi_level0.cpp +++ b/sycl/plugins/level_zero/pi_level0.cpp @@ -565,6 +565,28 @@ pi_result piPlatformGetInfo(pi_platform Platform, pi_platform_info ParamName, return PI_SUCCESS; } +pi_result piextPlatformGetNativeHandle(pi_platform Platform, + pi_native_handle *NativeHandle) { + assert(Platform); + assert(NativeHandle); + + auto ZeDriver = pi_cast(NativeHandle); + // Extract the L0 driver handle from the given PI platform + *ZeDriver = Platform->ZeDriver; + return PI_SUCCESS; +} + +pi_result piextPlatformCreateWithNativeHandle(pi_native_handle NativeHandle, + pi_platform *Platform) { + assert(NativeHandle); + assert(Platform); + + // Create PI platform from the given L0 driver handle. + auto ZeDriver = pi_cast(NativeHandle); + *Platform = new _pi_platform(ZeDriver); + return PI_SUCCESS; +} + pi_result piDevicesGet(pi_platform Platform, pi_device_type DeviceType, pi_uint32 NumEntries, pi_device *Devices, pi_uint32 *NumDevices) { diff --git a/sycl/plugins/opencl/pi_opencl.cpp b/sycl/plugins/opencl/pi_opencl.cpp index 8c3e3428593d3..dd51a6501d26a 100644 --- a/sycl/plugins/opencl/pi_opencl.cpp +++ b/sycl/plugins/opencl/pi_opencl.cpp @@ -176,6 +176,14 @@ pi_result piPlatformsGet(pi_uint32 num_entries, pi_platform *platforms, return static_cast(result); } +pi_result piextPlatformCreateWithNativeHandle(pi_native_handle nativeHandle, + pi_platform *platform) { + assert(platform); + assert(nativeHandle); + *platform = reinterpret_cast(nativeHandle); + return PI_SUCCESS; +} + // Example of a PI interface that does not map exactly to an OpenCL one. pi_result piDevicesGet(pi_platform platform, pi_device_type device_type, pi_uint32 num_entries, pi_device *devices, @@ -1072,6 +1080,11 @@ static pi_result piextGetNativeHandle(void *piObj, return PI_SUCCESS; } +pi_result piextPlatformGetNativeHandle(pi_platform platform, + pi_native_handle *nativeHandle) { + return piextGetNativeHandle(platform, nativeHandle); +} + pi_result piextDeviceGetNativeHandle(pi_device device, pi_native_handle *nativeHandle) { return piextGetNativeHandle(device, nativeHandle); @@ -1113,6 +1126,9 @@ pi_result piPluginInit(pi_plugin *PluginInit) { // Platform _PI_CL(piPlatformsGet, piPlatformsGet) _PI_CL(piPlatformGetInfo, clGetPlatformInfo) + _PI_CL(piextPlatformGetNativeHandle, piextPlatformGetNativeHandle) + _PI_CL(piextPlatformCreateWithNativeHandle, + piextPlatformCreateWithNativeHandle) // Device _PI_CL(piDevicesGet, piDevicesGet) _PI_CL(piDeviceGetInfo, clGetDeviceInfo) diff --git a/sycl/source/CMakeLists.txt b/sycl/source/CMakeLists.txt index f50eabd501f78..004b596e84955 100644 --- a/sycl/source/CMakeLists.txt +++ b/sycl/source/CMakeLists.txt @@ -94,6 +94,7 @@ endfunction(add_sycl_rt_library) set(SYCL_SOURCES "${sycl_inc_dir}/CL/sycl.hpp" + "backend/opencl.cpp" "detail/accessor_impl.cpp" "detail/buffer_impl.cpp" "detail/builtins_common.cpp" diff --git a/sycl/source/backend/opencl.cpp b/sycl/source/backend/opencl.cpp new file mode 100644 index 0000000000000..20f0add1f85d6 --- /dev/null +++ b/sycl/source/backend/opencl.cpp @@ -0,0 +1,88 @@ +//==------- opencl.cpp - SYCL OpenCL backend -------------------------------==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include +#include + +__SYCL_INLINE_NAMESPACE(cl) { +namespace sycl { +namespace opencl { +using namespace detail; + +//---------------------------------------------------------------------------- +// Implementation of opencl::make +__SYCL_EXPORT platform make_platform(pi_native_handle NativeHandle) { + const auto &Plugin = pi::getPlugin(); + // Create PI platform first. + pi::PiPlatform PiPlatform; + Plugin.call(NativeHandle, + &PiPlatform); + + // Construct the SYCL platform from PI platfrom. + return detail::createSyclObjFromImpl( + std::make_shared(PiPlatform, Plugin)); +} + +//---------------------------------------------------------------------------- +// Implementation of opencl::make +__SYCL_EXPORT device make_device(pi_native_handle NativeHandle) { + const auto &Plugin = pi::getPlugin(); + // Create PI device first. + pi::PiDevice PiDevice; + Plugin.call(NativeHandle, + &PiDevice); + // Construct the SYCL device from PI device. + return detail::createSyclObjFromImpl( + std::make_shared(PiDevice, Plugin)); +} + +//---------------------------------------------------------------------------- +// Implementation of opencl::make +__SYCL_EXPORT context make_context(pi_native_handle NativeHandle) { + const auto &Plugin = pi::getPlugin(); + // Create PI context first. + pi::PiContext PiContext; + Plugin.call(NativeHandle, + &PiContext); + // Construct the SYCL context from PI context. + return detail::createSyclObjFromImpl( + std::make_shared(PiContext, async_handler{}, Plugin)); +} + +//---------------------------------------------------------------------------- +// Implementation of opencl::make +__SYCL_EXPORT program make_program(const context &Context, + pi_native_handle NativeHandle) { + // Construct the SYCL program from native program. + // TODO: move here the code that creates PI program, and remove the + // native interop constructor. + return detail::createSyclObjFromImpl( + std::make_shared(getSyclObjImpl(Context), NativeHandle)); +} + +//---------------------------------------------------------------------------- +// Implementation of opencl::make +__SYCL_EXPORT queue make_queue(const context &Context, + pi_native_handle NativeHandle) { + const auto &Plugin = pi::getPlugin(); + const auto &ContextImpl = getSyclObjImpl(Context); + // Create PI queue first. + pi::PiQueue PiQueue; + Plugin.call(NativeHandle, + &PiQueue); + // Construct the SYCL queue from PI queue. + return detail::createSyclObjFromImpl(std::make_shared( + PiQueue, ContextImpl, ContextImpl->get_async_handler())); +} + +} // namespace opencl +} // namespace sycl +} // __SYCL_INLINE_NAMESPACE(cl) diff --git a/sycl/source/detail/pi.cpp b/sycl/source/detail/pi.cpp index 7190a927b5041..b00844cf85a59 100644 --- a/sycl/source/detail/pi.cpp +++ b/sycl/source/detail/pi.cpp @@ -372,6 +372,25 @@ static void initializePlugins(vector_class *Plugins) { #endif } +// Get the plugin serving given backend. +template const plugin &getPlugin() { + static const plugin *Plugin = nullptr; + if (Plugin) + return *Plugin; + + const vector_class &Plugins = pi::initialize(); + for (const auto &P : Plugins) + if (P.getBackend() == BE) { + Plugin = &P; + return *Plugin; + } + + throw runtime_error("pi::getPlugin couldn't find plugin", + PI_INVALID_OPERATION); +} + +template const plugin &getPlugin(); + // Report error and no return (keeps compiler from printing warnings). // TODO: Probably change that to throw a catchable exception, // but for now it is useful to see every failure. diff --git a/sycl/source/detail/platform_impl.cpp b/sycl/source/detail/platform_impl.cpp index daabe5722f754..ed8724e92179f 100644 --- a/sycl/source/detail/platform_impl.cpp +++ b/sycl/source/detail/platform_impl.cpp @@ -276,6 +276,13 @@ bool platform_impl::has_extension(const string_class &ExtensionName) const { return (AllExtensionNames.find(ExtensionName) != std::string::npos); } +pi_native_handle platform_impl::getNative() const { + const auto &Plugin = getPlugin(); + pi_native_handle Handle; + Plugin.call(getHandleRef(), &Handle); + return Handle; +} + template typename info::param_traits::return_type platform_impl::get_info() const { diff --git a/sycl/source/detail/platform_impl.hpp b/sycl/source/detail/platform_impl.hpp index 55c2f252b4cc3..8f2477d567ea1 100644 --- a/sycl/source/detail/platform_impl.hpp +++ b/sycl/source/detail/platform_impl.hpp @@ -120,6 +120,11 @@ class platform_impl { MPlugin = std::move(PluginPtr); } + /// Gets the native handle of the SYCL platform. + /// + /// \return a native handle. + pi_native_handle getNative() const; + private: bool MHostPlatform = false; RT::PiPlatform MPlatform = 0; diff --git a/sycl/source/platform.cpp b/sycl/source/platform.cpp index 25e2e8bdd9292..a40d7f7a2170b 100644 --- a/sycl/source/platform.cpp +++ b/sycl/source/platform.cpp @@ -49,6 +49,8 @@ platform::get_info() const { return impl->get_info(); } +pi_native_handle platform::getNative() const { return impl->getNative(); } + #define PARAM_TRAITS_SPEC(param_type, param, ret_type) \ template __SYCL_EXPORT ret_type \ platform::get_info() const; diff --git a/sycl/test/abi/pi_level0_symbol_check.dump b/sycl/test/abi/pi_level0_symbol_check.dump index df2b0ed30c4e0..68b2d0c0e0c6b 100644 --- a/sycl/test/abi/pi_level0_symbol_check.dump +++ b/sycl/test/abi/pi_level0_symbol_check.dump @@ -99,4 +99,6 @@ piEnqueueMemBufferReadRect piMemBufferPartition piEnqueueMemBufferWriteRect piextUSMHostAlloc +piextPlatformGetNativeHandle +piextPlatformCreateWithNativeHandle diff --git a/sycl/test/abi/pi_opencl_symbol_check.dump b/sycl/test/abi/pi_opencl_symbol_check.dump index 5076defbafa8a..529b64f006b6b 100644 --- a/sycl/test/abi/pi_opencl_symbol_check.dump +++ b/sycl/test/abi/pi_opencl_symbol_check.dump @@ -44,3 +44,5 @@ piextUSMFree piextUSMGetMemAllocInfo piextUSMHostAlloc piextUSMSharedAlloc +piextPlatformGetNativeHandle +piextPlatformCreateWithNativeHandle diff --git a/sycl/test/abi/sycl_symbols_linux.dump b/sycl/test/abi/sycl_symbols_linux.dump index 28c142ac53365..e975f36913e2a 100644 --- a/sycl/test/abi/sycl_symbols_linux.dump +++ b/sycl/test/abi/sycl_symbols_linux.dump @@ -3223,9 +3223,9 @@ _ZN2cl4sycl6detail14host_half_impl4halfmIERKS3_ _ZN2cl4sycl6detail14host_half_impl4halfmLERKS3_ _ZN2cl4sycl6detail14host_half_impl4halfpLERKS3_ _ZN2cl4sycl6detail15getOrWaitEventsESt6vectorINS0_5eventESaIS3_EESt10shared_ptrINS1_12context_implEE +_ZN2cl4sycl6detail16AccessorImplHost6resizeEm _ZN2cl4sycl6detail16AccessorImplHostD1Ev _ZN2cl4sycl6detail16AccessorImplHostD2Ev -_ZN2cl4sycl6detail16AccessorImplHost6resizeEm _ZN2cl4sycl6detail17HostProfilingInfo3endEv _ZN2cl4sycl6detail17HostProfilingInfo5startEv _ZN2cl4sycl6detail18convertChannelTypeE22_pi_image_channel_type @@ -3263,6 +3263,11 @@ _ZN2cl4sycl6kernelC2EP10_cl_kernelRKNS0_7contextE _ZN2cl4sycl6kernelC2ESt10shared_ptrINS0_6detail11kernel_implEE _ZN2cl4sycl6mallocEmRKNS0_5queueENS0_3usm5allocE _ZN2cl4sycl6mallocEmRKNS0_6deviceERKNS0_7contextENS0_3usm5allocE +_ZN2cl4sycl6opencl10make_queueERKNS0_7contextEm +_ZN2cl4sycl6opencl11make_deviceEm +_ZN2cl4sycl6opencl12make_contextEm +_ZN2cl4sycl6opencl12make_programERKNS0_7contextEm +_ZN2cl4sycl6opencl13make_platformEm _ZN2cl4sycl6streamC1EmmRNS0_7handlerE _ZN2cl4sycl6streamC2EmmRNS0_7handlerE _ZN2cl4sycl7contextC1EP11_cl_contextSt8functionIFvNS0_14exception_listEEE @@ -3527,10 +3532,10 @@ _ZNK2cl4sycl8platform8get_infoILNS0_4info8platformE2305EEENS3_12param_traitsIS4_ _ZNK2cl4sycl8platform8get_infoILNS0_4info8platformE2306EEENS3_12param_traitsIS4_XT_EE11return_typeEv _ZNK2cl4sycl8platform8get_infoILNS0_4info8platformE2307EEENS3_12param_traitsIS4_XT_EE11return_typeEv _ZNK2cl4sycl8platform8get_infoILNS0_4info8platformE2308EEENS3_12param_traitsIS4_XT_EE11return_typeEv +_ZNK2cl4sycl8platform9getNativeEv _ZNK2cl4sycl9exception11get_cl_codeEv _ZNK2cl4sycl9exception11get_contextEv _ZNK2cl4sycl9exception11has_contextEv _ZNK2cl4sycl9exception4whatEv __sycl_register_lib __sycl_unregister_lib - diff --git a/sycl/test/basic_tests/handler/interop_task.cpp b/sycl/test/basic_tests/handler/interop_task.cpp index d7ee3c0ea30e0..2cff0daf5da32 100644 --- a/sycl/test/basic_tests/handler/interop_task.cpp +++ b/sycl/test/basic_tests/handler/interop_task.cpp @@ -13,6 +13,7 @@ #include "CL/sycl/access/access.hpp" #include +#include #include "../../helpers.hpp" #include diff --git a/sycl/test/plugins/interop-opencl.cpp b/sycl/test/plugins/interop-opencl.cpp new file mode 100644 index 0000000000000..d46cd5ac315d5 --- /dev/null +++ b/sycl/test/plugins/interop-opencl.cpp @@ -0,0 +1,47 @@ +// REQUIRES: opencl + +// RUN: %clangxx -fsycl -fsycl-targets=%sycl_triple -I %sycl_source_dir %s -o %t.out +// RUN: env SYCL_BE=PI_OPENCL %CPU_RUN_PLACEHOLDER %t.out +// RUN: env SYCL_BE=PI_OPENCL %GPU_RUN_PLACEHOLDER %t.out +// RUN: env SYCL_BE=PI_OPENCL %ACC_RUN_PLACEHOLDER %t.out + +//==-- interop-opencl.cpp - SYCL test for OpenCL interop API --------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include +#include +#include + +using namespace cl::sycl; + +int main() { + queue Queue{}; + auto Context = Queue.get_info(); + auto Device = Queue.get_info(); + auto Platform = Device.get_info(); + + // Get native OpenCL handles + auto ocl_platform = Platform.get_native(); + auto ocl_device = Device.get_native(); + auto ocl_context = Context.get_native(); + auto ocl_queue = Queue.get_native(); + + // Re-create SYCL objects from native OpenCL handles + auto PlatformInterop = opencl::make(ocl_platform); + auto DeviceInterop = opencl::make(ocl_device); + auto ContextInterop = opencl::make(ocl_context); + auto QueueInterop = opencl::make(ContextInterop, ocl_queue); + + // Check native handles + assert(ocl_platform == PlatformInterop.get_native()); + assert(ocl_device == DeviceInterop.get_native()); + assert(ocl_context == ContextInterop.get_native()); + assert(ocl_queue == QueueInterop.get_native()); + + return 0; +}