diff --git a/include/ur_api.h b/include/ur_api.h index ae736e4675..291ae18ac1 100644 --- a/include/ur_api.h +++ b/include/ur_api.h @@ -1615,9 +1615,9 @@ typedef struct ur_platform_native_properties_t { ur_structure_type_t stype; /// [in,out][optional] pointer to extension-specific structure void *pNext; - /// [in] Indicates UR owns the native handle or if it came from an - /// interoperability operation in the application that asked to not - /// transfer the ownership to the unified-runtime. + /// [in] If true then ownership of the native handle is transferred to + /// the resultant object. This means the object will be responsible for + /// releasing the native resources at the end of its lifetime. bool isNativeHandleOwned; } ur_platform_native_properties_t; @@ -2696,9 +2696,9 @@ typedef struct ur_device_native_properties_t { ur_structure_type_t stype; /// [in,out][optional] pointer to extension-specific structure void *pNext; - /// [in] Indicates UR owns the native handle or if it came from an - /// interoperability operation in the application that asked to not - /// transfer the ownership to the unified-runtime. + /// [in] If true then ownership of the native handle is transferred to + /// the resultant object. This means the object will be responsible for + /// releasing the native resources at the end of its lifetime. bool isNativeHandleOwned; } ur_device_native_properties_t; @@ -3076,9 +3076,9 @@ typedef struct ur_context_native_properties_t { ur_structure_type_t stype; /// [in,out][optional] pointer to extension-specific structure void *pNext; - /// [in] Indicates UR owns the native handle or if it came from an - /// interoperability operation in the application that asked to not transfer - /// the ownership to the unified-runtime. + /// [in] If true then ownership of the native handle is transferred to + /// the resultant object. This means the object will be responsible for + /// releasing the native resources at the end of its lifetime. bool isNativeHandleOwned; } ur_context_native_properties_t; @@ -3697,9 +3697,9 @@ typedef struct ur_mem_native_properties_t { ur_structure_type_t stype; /// [in,out][optional] pointer to extension-specific structure void *pNext; - /// [in] Indicates UR owns the native handle or if it came from an - /// interoperability operation in the application that asked to not - /// transfer the ownership to the unified-runtime. + /// [in] If true then ownership of the native handle is transferred to + /// the resultant object. This means the object will be responsible for + /// releasing the native resources at the end of its lifetime. bool isNativeHandleOwned; } ur_mem_native_properties_t; @@ -4103,9 +4103,9 @@ typedef struct ur_sampler_native_properties_t { ur_structure_type_t stype; /// [in,out][optional] pointer to extension-specific structure void *pNext; - /// [in] Indicates UR owns the native handle or if it came from an - /// interoperability operation in the application that asked to not - /// transfer the ownership to the unified-runtime. + /// [in] If true then ownership of the native handle is transferred to + /// the resultant object. This means the object will be responsible for + /// releasing the native resources at the end of its lifetime. bool isNativeHandleOwned; } ur_sampler_native_properties_t; @@ -5811,9 +5811,9 @@ typedef struct ur_program_native_properties_t { ur_structure_type_t stype; /// [in,out][optional] pointer to extension-specific structure void *pNext; - /// [in] Indicates UR owns the native handle or if it came from an - /// interoperability operation in the application that asked to not - /// transfer the ownership to the unified-runtime. + /// [in] If true then ownership of the native handle is transferred to + /// the resultant object. This means the object will be responsible for + /// releasing the native resources at the end of its lifetime. bool isNativeHandleOwned; } ur_program_native_properties_t; @@ -6480,9 +6480,9 @@ typedef struct ur_kernel_native_properties_t { ur_structure_type_t stype; /// [in,out][optional] pointer to extension-specific structure void *pNext; - /// [in] Indicates UR owns the native handle or if it came from an - /// interoperability operation in the application that asked to not transfer - /// the ownership to the unified-runtime. + /// [in] If true then ownership of the native handle is transferred to + /// the resultant object. This means the object will be responsible for + /// releasing the native resources at the end of its lifetime. bool isNativeHandleOwned; } ur_kernel_native_properties_t; @@ -6875,9 +6875,9 @@ typedef struct ur_queue_native_properties_t { ur_structure_type_t stype; /// [in,out][optional] pointer to extension-specific structure void *pNext; - /// [in] Indicates UR owns the native handle or if it came from an - /// interoperability operation in the application that asked to not transfer - /// the ownership to the unified-runtime. + /// [in] If true then ownership of the native handle is transferred to + /// the resultant object. This means the object will be responsible for + /// releasing the native resources at the end of its lifetime. bool isNativeHandleOwned; } ur_queue_native_properties_t; @@ -7301,9 +7301,9 @@ typedef struct ur_event_native_properties_t { ur_structure_type_t stype; /// [in,out][optional] pointer to extension-specific structure void *pNext; - /// [in] Indicates UR owns the native handle or if it came from an - /// interoperability operation in the application that asked to not transfer - /// the ownership to the unified-runtime. + /// [in] If true then ownership of the native handle is transferred to + /// the resultant object. This means the object will be responsible for + /// releasing the native resources at the end of its lifetime. bool isNativeHandleOwned; } ur_event_native_properties_t; diff --git a/scripts/core/PROG.rst b/scripts/core/PROG.rst index 54123bbc1f..068869370d 100644 --- a/scripts/core/PROG.rst +++ b/scripts/core/PROG.rst @@ -287,17 +287,6 @@ ${x}QueueRetain. An application must call ${x}QueueRelease when a queue object is no longer needed. When a queue object's reference count becomes zero, it is deleted by the runtime. -Native Driver Access ----------------------------------- - -The runtime API provides accessors for native handles. -For example, given a ${x}_program_handle_t, we can -call ${x}ProgramGetNativeHandle to retrieve a ${x}_native_handle_t. -We can then leverage a platform extension to convert the -native handle to a driver handle. For example, OpenCL platform -may expose an extension ${x}ProgramCreateWithNativeHandle to retrieve -a cl_program. - Memory ====== @@ -340,3 +329,38 @@ through ${x}_usm_desc_t structure. Allocations that specify different pool handl isolated and not reside on the same page. Memory pool is subject to limits specified during pool creation. Even if no ${x}_usm_pool_handle_t is provided to an allocation function, each adapter may still perform memory pooling. + +Native Handles +============== + +In addition to the regular object creation APIs, ${X} objects can be +constructed with handles obtained directly from an adapter's associated +backend. This is achieved by casting the backend handle to a +${x}_native_handle_t and passing it to the relevant ``CreateWithNativeHandle`` +entry point. + + +.. note:: + Not all backends have a 1:1 equivalent for every ${X} handle type, as such + any ``CreateWithNativeHandle`` or ``GetNativeHandle`` entry point *may* fail + with the error code ${X}_RESULT_ERROR_UNSUPPORTED_FEATURE for a given + adapter. + +Native Handle Ownership +----------------------- + +By default a ${X} object constructed from a native handle doesn't own the +native handle, it is guaranteed not to retain a reference to the native handle, +or cause its resources to be released. A ${X} object that doesn't own its +associated native handle **must** be destroyed before the native handle is. + +Ownership of the native handle can be transferred to the ${X} object by passing +``isNativeHandleOwned = true`` in the native properties struct when calling the +``CreateWithNativeHandle`` entry point. A ${X} object that owns a native handle +will attempt to release the native resources associated with that handle on +destruction. The same native handle **must not** have its ownership transferred +to more than one ${X} object. + +Ownership of a native handle obtained from a ${X} object via a +``GetNativeHandle`` entry point **must not** be transferred to a new ${X} +object. diff --git a/scripts/core/context.yml b/scripts/core/context.yml index 9b316a21a7..eb2324a56f 100644 --- a/scripts/core/context.yml +++ b/scripts/core/context.yml @@ -209,9 +209,9 @@ members: - type: bool name: isNativeHandleOwned desc: | - [in] Indicates UR owns the native handle or if it came from an interoperability - operation in the application that asked to not transfer the ownership to - the unified-runtime. + [in] If true then ownership of the native handle is transferred to + the resultant object. This means the object will be responsible for + releasing the native resources at the end of its lifetime. --- #-------------------------------------------------------------------------- type: function desc: "Create runtime context object from native context handle." diff --git a/scripts/core/device.yml b/scripts/core/device.yml index ce671c24d6..0cbb3e31a4 100644 --- a/scripts/core/device.yml +++ b/scripts/core/device.yml @@ -803,10 +803,10 @@ base: $x_base_properties_t members: - type: bool name: isNativeHandleOwned - desc: > - [in] Indicates UR owns the native handle or if it came from an - interoperability operation in the application that asked to not - transfer the ownership to the unified-runtime. + desc: | + [in] If true then ownership of the native handle is transferred to + the resultant object. This means the object will be responsible for + releasing the native resources at the end of its lifetime. --- #-------------------------------------------------------------------------- type: function desc: "Create runtime device object from native device handle." diff --git a/scripts/core/event.yml b/scripts/core/event.yml index 4e93faa9f3..91418a9955 100644 --- a/scripts/core/event.yml +++ b/scripts/core/event.yml @@ -289,9 +289,9 @@ members: - type: bool name: isNativeHandleOwned desc: | - [in] Indicates UR owns the native handle or if it came from an interoperability - operation in the application that asked to not transfer the ownership to - the unified-runtime. + [in] If true then ownership of the native handle is transferred to + the resultant object. This means the object will be responsible for + releasing the native resources at the end of its lifetime. --- #-------------------------------------------------------------------------- type: function desc: "Create runtime event object from native event handle." diff --git a/scripts/core/kernel.yml b/scripts/core/kernel.yml index 8551337059..00c24f6036 100644 --- a/scripts/core/kernel.yml +++ b/scripts/core/kernel.yml @@ -513,9 +513,9 @@ members: - type: bool name: isNativeHandleOwned desc: | - [in] Indicates UR owns the native handle or if it came from an interoperability - operation in the application that asked to not transfer the ownership to - the unified-runtime. + [in] If true then ownership of the native handle is transferred to + the resultant object. This means the object will be responsible for + releasing the native resources at the end of its lifetime. --- #-------------------------------------------------------------------------- type: function desc: "Create runtime kernel object from native kernel handle." diff --git a/scripts/core/memory.yml b/scripts/core/memory.yml index 467e10d749..75f68d8e9a 100644 --- a/scripts/core/memory.yml +++ b/scripts/core/memory.yml @@ -474,10 +474,10 @@ base: $x_base_properties_t members: - type: bool name: isNativeHandleOwned - desc: > - [in] Indicates UR owns the native handle or if it came from an - interoperability operation in the application that asked to not - transfer the ownership to the unified-runtime. + desc: | + [in] If true then ownership of the native handle is transferred to + the resultant object. This means the object will be responsible for + releasing the native resources at the end of its lifetime. --- #-------------------------------------------------------------------------- type: function desc: "Create runtime buffer memory object from native memory handle." diff --git a/scripts/core/platform.yml b/scripts/core/platform.yml index f0f7faacd7..059d6e6401 100644 --- a/scripts/core/platform.yml +++ b/scripts/core/platform.yml @@ -202,10 +202,10 @@ base: $x_base_properties_t members: - type: bool name: isNativeHandleOwned - desc: > - [in] Indicates UR owns the native handle or if it came from an - interoperability operation in the application that asked to not - transfer the ownership to the unified-runtime. + desc: | + [in] If true then ownership of the native handle is transferred to + the resultant object. This means the object will be responsible for + releasing the native resources at the end of its lifetime. --- #-------------------------------------------------------------------------- type: function desc: "Create runtime platform object from native platform handle." diff --git a/scripts/core/program.yml b/scripts/core/program.yml index 0449a58d6d..66a6e890b4 100644 --- a/scripts/core/program.yml +++ b/scripts/core/program.yml @@ -584,10 +584,10 @@ base: $x_base_properties_t members: - type: bool name: isNativeHandleOwned - desc: > - [in] Indicates UR owns the native handle or if it came from an - interoperability operation in the application that asked to not - transfer the ownership to the unified-runtime. + desc: | + [in] If true then ownership of the native handle is transferred to + the resultant object. This means the object will be responsible for + releasing the native resources at the end of its lifetime. --- #-------------------------------------------------------------------------- type: function desc: "Create runtime program object from native program handle." diff --git a/scripts/core/queue.yml b/scripts/core/queue.yml index cd8bd2668e..470bbf8fae 100644 --- a/scripts/core/queue.yml +++ b/scripts/core/queue.yml @@ -262,9 +262,9 @@ members: - type: bool name: isNativeHandleOwned desc: | - [in] Indicates UR owns the native handle or if it came from an interoperability - operation in the application that asked to not transfer the ownership to - the unified-runtime. + [in] If true then ownership of the native handle is transferred to + the resultant object. This means the object will be responsible for + releasing the native resources at the end of its lifetime. --- #-------------------------------------------------------------------------- type: function desc: "Create runtime queue object from native queue handle." diff --git a/scripts/core/sampler.yml b/scripts/core/sampler.yml index 7e555386b0..6bc86857ed 100644 --- a/scripts/core/sampler.yml +++ b/scripts/core/sampler.yml @@ -206,10 +206,10 @@ base: $x_base_properties_t members: - type: bool name: isNativeHandleOwned - desc: > - [in] Indicates UR owns the native handle or if it came from an - interoperability operation in the application that asked to not - transfer the ownership to the unified-runtime. + desc: | + [in] If true then ownership of the native handle is transferred to + the resultant object. This means the object will be responsible for + releasing the native resources at the end of its lifetime. --- #-------------------------------------------------------------------------- type: function desc: "Create runtime sampler object from native sampler handle." diff --git a/source/adapters/cuda/queue.cpp b/source/adapters/cuda/queue.cpp index 548940f853..b9779f37be 100644 --- a/source/adapters/cuda/queue.cpp +++ b/source/adapters/cuda/queue.cpp @@ -284,17 +284,19 @@ UR_APIEXPORT ur_result_t UR_APICALL urQueueCreateWithNativeHandle( std::vector ComputeCuStreams(1, CuStream); std::vector TransferCuStreams(0); + auto isNativeHandleOwned = + pProperties ? pProperties->isNativeHandleOwned : false; + // Create queue and set num_compute_streams to 1, as computeCuStreams has // valid stream - *phQueue = - new ur_queue_handle_t_{std::move(ComputeCuStreams), - std::move(TransferCuStreams), - hContext, - hDevice, - CuFlags, - Flags, - /*priority*/ 0, - /*backend_owns*/ pProperties->isNativeHandleOwned}; + *phQueue = new ur_queue_handle_t_{std::move(ComputeCuStreams), + std::move(TransferCuStreams), + hContext, + hDevice, + CuFlags, + Flags, + /*priority*/ 0, + /*backend_owns*/ isNativeHandleOwned}; (*phQueue)->NumComputeStreams = 1; return UR_RESULT_SUCCESS; diff --git a/source/adapters/hip/memory.cpp b/source/adapters/hip/memory.cpp index 96cd53bd9a..92d0ec4fbe 100644 --- a/source/adapters/hip/memory.cpp +++ b/source/adapters/hip/memory.cpp @@ -302,6 +302,9 @@ UR_APIEXPORT ur_result_t UR_APICALL urMemGetNativeHandle(ur_mem_handle_t hMem, ur_device_handle_t Device, ur_native_handle_t *phNativeMem) { UR_ASSERT(Device != nullptr, UR_RESULT_ERROR_INVALID_NULL_HANDLE); + if (hMem->isImage()) { + return UR_RESULT_ERROR_UNSUPPORTED_FEATURE; + } #if defined(__HIP_PLATFORM_NVIDIA__) if (sizeof(BufferMem::native_type) > sizeof(ur_native_handle_t)) { // Check that all the upper bits that cannot be represented by diff --git a/source/adapters/hip/queue.cpp b/source/adapters/hip/queue.cpp index 5ab28d45ba..94177e097d 100644 --- a/source/adapters/hip/queue.cpp +++ b/source/adapters/hip/queue.cpp @@ -318,17 +318,19 @@ UR_APIEXPORT ur_result_t UR_APICALL urQueueCreateWithNativeHandle( std::vector ComputeHIPStreams(1, HIPStream); std::vector TransferHIPStreams(0); + auto isNativeHandleOwned = + pProperties ? pProperties->isNativeHandleOwned : false; + // Create queue and set num_compute_streams to 1, as computeHIPStreams has // valid stream - *phQueue = - new ur_queue_handle_t_{std::move(ComputeHIPStreams), - std::move(TransferHIPStreams), - hContext, - hDevice, - HIPFlags, - Flags, - /*priority*/ 0, - /*backend_owns*/ pProperties->isNativeHandleOwned}; + *phQueue = new ur_queue_handle_t_{std::move(ComputeHIPStreams), + std::move(TransferHIPStreams), + hContext, + hDevice, + HIPFlags, + Flags, + /*priority*/ 0, + /*backend_owns*/ isNativeHandleOwned}; (*phQueue)->NumComputeStreams = 1; return UR_RESULT_SUCCESS; diff --git a/source/adapters/level_zero/context.cpp b/source/adapters/level_zero/context.cpp index 6f189fa00b..67dcd513e5 100644 --- a/source/adapters/level_zero/context.cpp +++ b/source/adapters/level_zero/context.cpp @@ -159,7 +159,7 @@ ur_result_t urContextCreateWithNativeHandle( const ur_context_native_properties_t *Properties, /// [out] pointer to the handle of the context object created. ur_context_handle_t *Context) { - bool OwnNativeHandle = Properties->isNativeHandleOwned; + bool OwnNativeHandle = Properties ? Properties->isNativeHandleOwned : false; try { ze_context_handle_t ZeContext = reinterpret_cast(NativeContext); diff --git a/source/adapters/level_zero/kernel.cpp b/source/adapters/level_zero/kernel.cpp index b07bf044af..4a0bfc3da5 100644 --- a/source/adapters/level_zero/kernel.cpp +++ b/source/adapters/level_zero/kernel.cpp @@ -1118,9 +1118,9 @@ ur_result_t urKernelCreateWithNativeHandle( ze_kernel_handle_t ZeKernel = ur_cast(NativeKernel); ur_kernel_handle_t_ *Kernel = nullptr; try { - Kernel = new ur_kernel_handle_t_(ZeKernel, Properties->isNativeHandleOwned, - Context); - if (Properties->isNativeHandleOwned) { + auto OwnNativeHandle = Properties ? Properties->isNativeHandleOwned : false; + Kernel = new ur_kernel_handle_t_(ZeKernel, OwnNativeHandle, Context); + if (OwnNativeHandle) { // If ownership is passed to the adapter we need to pass the kernel // to this vector which is then used during ZeKernelRelease. Kernel->ZeKernels.push_back(ZeKernel); diff --git a/source/adapters/level_zero/memory.cpp b/source/adapters/level_zero/memory.cpp index a5c5ef9590..e21470eee2 100644 --- a/source/adapters/level_zero/memory.cpp +++ b/source/adapters/level_zero/memory.cpp @@ -1639,8 +1639,9 @@ ur_result_t urMemImageCreateWithNativeHandle( return Res; } - UR_CALL(createUrMemFromZeImage( - Context, ZeHImage, Properties->isNativeHandleOwned, ZeImageDesc, Mem)); + auto OwnNativeHandle = Properties ? Properties->isNativeHandleOwned : false; + UR_CALL(createUrMemFromZeImage(Context, ZeHImage, OwnNativeHandle, + ZeImageDesc, Mem)); return UR_RESULT_SUCCESS; } diff --git a/source/adapters/level_zero/program.cpp b/source/adapters/level_zero/program.cpp index 454f77cdc8..3f0790bddd 100644 --- a/source/adapters/level_zero/program.cpp +++ b/source/adapters/level_zero/program.cpp @@ -937,7 +937,8 @@ ur_result_t urProgramGetNativeHandle( } } if (!Module) - return UR_RESULT_ERROR_INVALID_OPERATION; + // L0 only supprts returning native handle from built programs. + return UR_RESULT_ERROR_UNSUPPORTED_FEATURE; *ZeModule = Module; return UR_RESULT_SUCCESS; diff --git a/source/adapters/opencl/ur_interface_loader.cpp b/source/adapters/opencl/ur_interface_loader.cpp index 7a3845a4d9..0ff80aed1e 100644 --- a/source/adapters/opencl/ur_interface_loader.cpp +++ b/source/adapters/opencl/ur_interface_loader.cpp @@ -159,6 +159,7 @@ urGetMemProcAddrTable(ur_api_version_t Version, ur_mem_dditable_t *pDdiTable) { pDdiTable->pfnGetNativeHandle = urMemGetNativeHandle; pDdiTable->pfnImageCreate = urMemImageCreate; pDdiTable->pfnImageGetInfo = urMemImageGetInfo; + pDdiTable->pfnImageCreateWithNativeHandle = urMemImageCreateWithNativeHandle; pDdiTable->pfnRelease = urMemRelease; pDdiTable->pfnRetain = urMemRetain; return UR_RESULT_SUCCESS; diff --git a/test/conformance/context/urContextCreateWithNativeHandle.cpp b/test/conformance/context/urContextCreateWithNativeHandle.cpp index c54cd74024..77b331de43 100644 --- a/test/conformance/context/urContextCreateWithNativeHandle.cpp +++ b/test/conformance/context/urContextCreateWithNativeHandle.cpp @@ -19,9 +19,8 @@ TEST_P(urContextCreateWithNativeHandleTest, Success) { // We can however convert the native_handle back into a unified-runtime handle // and perform some query on it to verify that it works. ur_context_handle_t ctx = nullptr; - ur_context_native_properties_t props{}; UUR_ASSERT_SUCCESS_OR_UNSUPPORTED(urContextCreateWithNativeHandle( - native_context, adapter, 1, &device, &props, &ctx)); + native_context, adapter, 1, &device, nullptr, &ctx)); ASSERT_NE(ctx, nullptr); uint32_t n_devices = 0; @@ -31,21 +30,8 @@ TEST_P(urContextCreateWithNativeHandleTest, Success) { ASSERT_SUCCESS(urContextRelease(ctx)); } -TEST_P(urContextCreateWithNativeHandleTest, SuccessWithOwnedNativeHandle) { - ur_native_handle_t native_context = 0; - - UUR_ASSERT_SUCCESS_OR_UNSUPPORTED( - urContextGetNativeHandle(context, &native_context)); - - ur_context_handle_t ctx = nullptr; - ur_context_native_properties_t props{ - UR_STRUCTURE_TYPE_CONTEXT_NATIVE_PROPERTIES, nullptr, true}; - UUR_ASSERT_SUCCESS_OR_UNSUPPORTED(urContextCreateWithNativeHandle( - native_context, adapter, 1, &device, &props, &ctx)); - ASSERT_NE(ctx, nullptr); -} - -TEST_P(urContextCreateWithNativeHandleTest, SuccessWithUnOwnedNativeHandle) { +TEST_P(urContextCreateWithNativeHandleTest, + SuccessExplicitUnOwnedNativeHandle) { ur_native_handle_t native_context = 0; UUR_ASSERT_SUCCESS_OR_UNSUPPORTED( diff --git a/test/conformance/device/urDeviceCreateWithNativeHandle.cpp b/test/conformance/device/urDeviceCreateWithNativeHandle.cpp index 3ff9c928b1..81ddfed87e 100644 --- a/test/conformance/device/urDeviceCreateWithNativeHandle.cpp +++ b/test/conformance/device/urDeviceCreateWithNativeHandle.cpp @@ -29,23 +29,9 @@ TEST_P(urDeviceCreateWithNativeHandleTest, Success) { &dev_id, nullptr)); } -TEST_P(urDeviceCreateWithNativeHandleTest, SuccessWithOwnedNativeHandle) { +TEST_F(urDeviceCreateWithNativeHandleTest, + SuccessWithExplicitUnOwnedNativeHandle) { ur_native_handle_t native_handle = 0; - - UUR_ASSERT_SUCCESS_OR_UNSUPPORTED( - urDeviceGetNativeHandle(device, &native_handle)); - - ur_device_handle_t dev = nullptr; - ur_device_native_properties_t props{ - UR_STRUCTURE_TYPE_DEVICE_NATIVE_PROPERTIES, nullptr, true}; - UUR_ASSERT_SUCCESS_OR_UNSUPPORTED( - urDeviceCreateWithNativeHandle(native_handle, adapter, &props, &dev)); - ASSERT_NE(dev, nullptr); -} - -TEST_P(urDeviceCreateWithNativeHandleTest, SuccessWithUnOwnedNativeHandle) { - ur_native_handle_t native_handle = 0; - UUR_ASSERT_SUCCESS_OR_UNSUPPORTED( urDeviceGetNativeHandle(device, &native_handle)); diff --git a/test/conformance/event/urEventCreateWithNativeHandle.cpp b/test/conformance/event/urEventCreateWithNativeHandle.cpp index b0ba7fe927..6b47fc642e 100644 --- a/test/conformance/event/urEventCreateWithNativeHandle.cpp +++ b/test/conformance/event/urEventCreateWithNativeHandle.cpp @@ -33,3 +33,26 @@ TEST_P(urEventCreateWithNativeHandleTest, Success) { sizeof(ur_execution_info_t), &exec_info, nullptr)); } + +TEST_P(urEventCreateWithNativeHandleTest, SuccessWithProperties) { + ur_native_handle_t native_event = 0; + { + UUR_ASSERT_SUCCESS_OR_UNSUPPORTED( + urEventGetNativeHandle(event, &native_event)); + } + + uur::raii::Event evt = nullptr; + // We can't pass isNativeHandleOwned = true in the generic tests since + // we always get the native handle from a UR object, and transferring + // ownership from one UR object to another isn't allowed. + ur_event_native_properties_t props = { + UR_STRUCTURE_TYPE_EVENT_NATIVE_PROPERTIES, nullptr, false}; + UUR_ASSERT_SUCCESS_OR_UNSUPPORTED( + urEventCreateWithNativeHandle(native_event, context, &props, evt.ptr())); + ASSERT_NE(evt, nullptr); + + ur_execution_info_t exec_info; + ASSERT_SUCCESS(urEventGetInfo(evt, UR_EVENT_INFO_COMMAND_EXECUTION_STATUS, + sizeof(ur_execution_info_t), &exec_info, + nullptr)); +} diff --git a/test/conformance/kernel/urKernelCreateWithNativeHandle.cpp b/test/conformance/kernel/urKernelCreateWithNativeHandle.cpp index 0874601854..8b0fe44d26 100644 --- a/test/conformance/kernel/urKernelCreateWithNativeHandle.cpp +++ b/test/conformance/kernel/urKernelCreateWithNativeHandle.cpp @@ -14,15 +14,11 @@ struct urKernelCreateWithNativeHandleTest : uur::urKernelTest { urKernelGetNativeHandle(kernel, &native_kernel_handle)); } - void TearDown() override { - if (native_kernel) { - EXPECT_SUCCESS(urKernelRelease(native_kernel)); - } - UUR_RETURN_ON_FATAL_FAILURE(urKernelTest::TearDown()); - } - ur_native_handle_t native_kernel_handle = 0; ur_kernel_handle_t native_kernel = nullptr; + // We can't pass isNativeHandleOwned = true in the generic tests since + // we always get the native handle from a UR object, and transferring + // ownership from one UR object to another isn't allowed. ur_kernel_native_properties_t properties = { UR_STRUCTURE_TYPE_KERNEL_NATIVE_PROPERTIES, /*sType*/ nullptr, /*pNext*/ @@ -32,6 +28,17 @@ struct urKernelCreateWithNativeHandleTest : uur::urKernelTest { UUR_INSTANTIATE_DEVICE_TEST_SUITE_P(urKernelCreateWithNativeHandleTest); TEST_P(urKernelCreateWithNativeHandleTest, Success) { + UUR_ASSERT_SUCCESS_OR_UNSUPPORTED(urKernelCreateWithNativeHandle( + native_kernel_handle, context, program, nullptr, &native_kernel)); + + uint32_t ref_count = 0; + ASSERT_SUCCESS(urKernelGetInfo(native_kernel, UR_KERNEL_INFO_REFERENCE_COUNT, + sizeof(ref_count), &ref_count, nullptr)); + + ASSERT_NE(ref_count, 0); +} + +TEST_P(urKernelCreateWithNativeHandleTest, SuccessWithProperties) { UUR_ASSERT_SUCCESS_OR_UNSUPPORTED(urKernelCreateWithNativeHandle( native_kernel_handle, context, program, &properties, &native_kernel)); diff --git a/test/conformance/memory/urMemBufferCreateWithNativeHandle.cpp b/test/conformance/memory/urMemBufferCreateWithNativeHandle.cpp index 2d09c962a4..c0bd46dc62 100644 --- a/test/conformance/memory/urMemBufferCreateWithNativeHandle.cpp +++ b/test/conformance/memory/urMemBufferCreateWithNativeHandle.cpp @@ -32,26 +32,29 @@ TEST_P(urMemBufferCreateWithNativeHandleTest, Success) { ASSERT_SUCCESS(urMemRelease(mem)); } -TEST_P(urMemBufferCreateWithNativeHandleTest, SuccessWithOwnedNativeHandle) { - ur_native_handle_t native_handle = 0; +TEST_P(urMemBufferCreateWithNativeHandleTest, SuccessWithProperties) { + ur_native_handle_t hNativeMem = 0; UUR_ASSERT_SUCCESS_OR_UNSUPPORTED( - urMemGetNativeHandle(buffer, device, &native_handle)); + urMemGetNativeHandle(buffer, device, &hNativeMem)); ur_mem_handle_t mem = nullptr; + // We can't pass isNativeHandleOwned = true in the generic tests since + // we always get the native handle from a UR object, and transferring + // ownership from one UR object to another isn't allowed. ur_mem_native_properties_t props = { /*.stype =*/UR_STRUCTURE_TYPE_MEM_NATIVE_PROPERTIES, /*.pNext =*/nullptr, - /*.isNativeHandleOwned =*/true, + /*.isNativeHandleOwned =*/false, }; UUR_ASSERT_SUCCESS_OR_UNSUPPORTED( - urMemBufferCreateWithNativeHandle(native_handle, context, &props, &mem)); - ASSERT_NE(nullptr, mem); + urMemBufferCreateWithNativeHandle(hNativeMem, context, &props, &mem)); + ASSERT_NE(mem, nullptr); - ur_context_handle_t mem_context = nullptr; - ASSERT_SUCCESS(urMemGetInfo(mem, UR_MEM_INFO_CONTEXT, - sizeof(ur_context_handle_t), &mem_context, - nullptr)); - ASSERT_EQ(context, mem_context); + size_t alloc_size = 0; + ASSERT_SUCCESS(urMemGetInfo(mem, UR_MEM_INFO_SIZE, sizeof(size_t), + &alloc_size, nullptr)); + + ASSERT_SUCCESS(urMemRelease(mem)); } TEST_P(urMemBufferCreateWithNativeHandleTest, SuccessWithUnOwnedNativeHandle) { diff --git a/test/conformance/memory/urMemImageCreateWithNativeHandle.cpp b/test/conformance/memory/urMemImageCreateWithNativeHandle.cpp index 811022d541..03452ae83c 100644 --- a/test/conformance/memory/urMemImageCreateWithNativeHandle.cpp +++ b/test/conformance/memory/urMemImageCreateWithNativeHandle.cpp @@ -17,7 +17,6 @@ UUR_INSTANTIATE_DEVICE_TEST_SUITE_P(urMemImageCreateWithNativeHandleTest); TEST_P(urMemImageCreateWithNativeHandleTest, Success) { UUR_KNOWN_FAILURE_ON(uur::HIP{}, uur::LevelZero{}); - ur_native_handle_t native_handle = 0; UUR_ASSERT_SUCCESS_OR_UNSUPPORTED( urMemGetNativeHandle(image, device, &native_handle)); @@ -34,6 +33,28 @@ TEST_P(urMemImageCreateWithNativeHandleTest, Success) { ASSERT_EQ(context, mem_context); } +TEST_P(urMemImageCreateWithNativeHandleTest, SuccessWithProperties) { + ur_native_handle_t native_handle = 0; + UUR_ASSERT_SUCCESS_OR_UNSUPPORTED( + urMemGetNativeHandle(image, device, &native_handle)); + + ur_mem_handle_t mem = nullptr; + ur_mem_native_properties_t props = {UR_STRUCTURE_TYPE_MEM_NATIVE_PROPERTIES, + nullptr, false}; + // We can't pass isNativeHandleOwned = true in the generic tests since + // we always get the native handle from a UR object, and transferring + // ownership from one UR object to another isn't allowed. + ASSERT_SUCCESS(urMemImageCreateWithNativeHandle( + native_handle, context, &image_format, &image_desc, &props, &mem)); + ASSERT_NE(nullptr, mem); + + ur_context_handle_t mem_context = nullptr; + ASSERT_SUCCESS(urMemGetInfo(mem, UR_MEM_INFO_CONTEXT, + sizeof(ur_context_handle_t), &mem_context, + nullptr)); + ASSERT_EQ(context, mem_context); +} + TEST_P(urMemImageCreateWithNativeHandleTest, InvalidNullHandle) { ur_native_handle_t native_handle = 0; ASSERT_SUCCESS(urMemGetNativeHandle(image, device, &native_handle)); diff --git a/test/conformance/platform/urPlatformCreateWithNativeHandle.cpp b/test/conformance/platform/urPlatformCreateWithNativeHandle.cpp index 2bffa1f5a1..5133c54d3a 100644 --- a/test/conformance/platform/urPlatformCreateWithNativeHandle.cpp +++ b/test/conformance/platform/urPlatformCreateWithNativeHandle.cpp @@ -37,29 +37,8 @@ TEST_P(urPlatformCreateWithNativeHandleTest, Success) { ASSERT_EQ(input_platform_name, created_platform_name); } -TEST_P(urPlatformCreateWithNativeHandleTest, SuccessWithOwnedNativeHandle) { - ur_native_handle_t native_handle = 0; - - UUR_ASSERT_SUCCESS_OR_UNSUPPORTED( - urPlatformGetNativeHandle(platform, &native_handle)); - - // We cannot assume anything about a native_handle, not even if it's - // `nullptr` since this could be a valid representation within a backend. - // We can however convert the native_handle back into a unified-runtime - // handle and perform some query on it to verify that it works. - ur_platform_native_properties_t props = { - UR_STRUCTURE_TYPE_PLATFORM_NATIVE_PROPERTIES, nullptr, true}; - ur_platform_handle_t plat = nullptr; - UUR_ASSERT_SUCCESS_OR_UNSUPPORTED( - urPlatformCreateWithNativeHandle(native_handle, adapter, &props, &plat)); - ASSERT_NE(plat, nullptr); - - std::string input_platform_name = uur::GetPlatformName(platform); - std::string created_platform_name = uur::GetPlatformName(plat); - ASSERT_EQ(input_platform_name, created_platform_name); -} - -TEST_P(urPlatformCreateWithNativeHandleTest, SuccessWithUnOwnedNativeHandle) { +TEST_F(urPlatformCreateWithNativeHandleTest, + SuccessWithExplicitUnOwnedNativeHandle) { ur_native_handle_t native_handle = 0; UUR_ASSERT_SUCCESS_OR_UNSUPPORTED( diff --git a/test/conformance/program/urProgramCreateWithNativeHandle.cpp b/test/conformance/program/urProgramCreateWithNativeHandle.cpp index 450e0e30ed..eca65dcac1 100644 --- a/test/conformance/program/urProgramCreateWithNativeHandle.cpp +++ b/test/conformance/program/urProgramCreateWithNativeHandle.cpp @@ -47,6 +47,24 @@ TEST_P(urProgramCreateWithNativeHandleTest, Success) { ASSERT_NE(ref_count, 0); } +TEST_P(urProgramCreateWithNativeHandleTest, SuccessWithProperties) { + // We can't pass isNativeHandleOwned = true in the generic tests since + // we always get the native handle from a UR object, and transferring + // ownership from one UR object to another isn't allowed. + ur_program_native_properties_t props = { + UR_STRUCTURE_TYPE_PROGRAM_NATIVE_PROPERTIES, nullptr, false}; + UUR_ASSERT_SUCCESS_OR_UNSUPPORTED(urProgramCreateWithNativeHandle( + native_program_handle, context, &props, &native_program)); + + uint32_t ref_count = 0; + + ASSERT_SUCCESS(urProgramGetInfo(native_program, + UR_PROGRAM_INFO_REFERENCE_COUNT, + sizeof(ref_count), &ref_count, nullptr)); + + ASSERT_NE(ref_count, 0); +} + TEST_P(urProgramCreateWithNativeHandleTest, InvalidNullHandleContext) { ASSERT_EQ_RESULT(UR_RESULT_ERROR_INVALID_NULL_HANDLE, urProgramCreateWithNativeHandle(native_program_handle, diff --git a/test/conformance/queue/urQueueCreateWithNativeHandle.cpp b/test/conformance/queue/urQueueCreateWithNativeHandle.cpp index 770d6d1511..564da6884d 100644 --- a/test/conformance/queue/urQueueCreateWithNativeHandle.cpp +++ b/test/conformance/queue/urQueueCreateWithNativeHandle.cpp @@ -13,13 +13,34 @@ TEST_P(urQueueCreateWithNativeHandleTest, Success) { UUR_ASSERT_SUCCESS_OR_UNSUPPORTED( urQueueGetNativeHandle(queue, nullptr, &native_handle)); + // We cannot assume anything about a native_handle, not even if it's + // `nullptr` since this could be a valid representation within a backend. + // We can however convert the native_handle back into a unified-runtime handle + // and perform some query on it to verify that it works. + ur_queue_handle_t q = nullptr; + ASSERT_SUCCESS(urQueueCreateWithNativeHandle(native_handle, context, device, + nullptr, &q)); + ASSERT_NE(q, nullptr); + + ur_context_handle_t q_context = nullptr; + ASSERT_SUCCESS(urQueueGetInfo(q, UR_QUEUE_INFO_CONTEXT, sizeof(q_context), + &q_context, nullptr)); + ASSERT_EQ(q_context, context); + ASSERT_SUCCESS(urQueueRelease(q)); +} +TEST_P(urQueueCreateWithNativeHandleTest, SuccessWithProperties) { + ur_native_handle_t native_handle = 0; + + UUR_ASSERT_SUCCESS_OR_UNSUPPORTED( + urQueueGetNativeHandle(queue, nullptr, &native_handle)); // We cannot assume anything about a native_handle, not even if it's // `nullptr` since this could be a valid representation within a backend. // We can however convert the native_handle back into a unified-runtime handle // and perform some query on it to verify that it works. ur_queue_handle_t q = nullptr; - ur_queue_native_properties_t properties{}; + ur_queue_native_properties_t properties = { + UR_STRUCTURE_TYPE_QUEUE_NATIVE_PROPERTIES, nullptr, false}; ASSERT_SUCCESS(urQueueCreateWithNativeHandle(native_handle, context, device, &properties, &q)); ASSERT_NE(q, nullptr); diff --git a/test/conformance/sampler/urSamplerCreateWithNativeHandle.cpp b/test/conformance/sampler/urSamplerCreateWithNativeHandle.cpp index daa95d0a8a..2cb7debad4 100644 --- a/test/conformance/sampler/urSamplerCreateWithNativeHandle.cpp +++ b/test/conformance/sampler/urSamplerCreateWithNativeHandle.cpp @@ -22,7 +22,31 @@ TEST_P(urSamplerCreateWithNativeHandleTest, Success) { // We can however convert the native_handle back into a unified-runtime handle // and perform some query on it to verify that it works. ur_sampler_handle_t hSampler = nullptr; - ur_sampler_native_properties_t props{}; + UUR_ASSERT_SUCCESS_OR_UNSUPPORTED(urSamplerCreateWithNativeHandle( + native_sampler, context, nullptr, &hSampler)); + ASSERT_NE(hSampler, nullptr); + + ur_sampler_addressing_mode_t addr_mode; + ASSERT_SUCCESS(urSamplerGetInfo(hSampler, UR_SAMPLER_INFO_ADDRESSING_MODE, + sizeof(addr_mode), &addr_mode, nullptr)); + ASSERT_EQ(addr_mode, sampler_desc.addressingMode); + ASSERT_SUCCESS(urSamplerRelease(hSampler)); +} + +TEST_P(urSamplerCreateWithNativeHandleTest, + SuccessExplicitUnOwnedNativeHandle) { + ur_native_handle_t native_sampler = 0; + + UUR_ASSERT_SUCCESS_OR_UNSUPPORTED( + urSamplerGetNativeHandle(sampler, &native_sampler)); + + // We cannot assume anything about a native_handle, not even if it's + // `nullptr` since this could be a valid representation within a backend. + // We can however convert the native_handle back into a unified-runtime handle + // and perform some query on it to verify that it works. + ur_sampler_handle_t hSampler = nullptr; + ur_sampler_native_properties_t props{ + UR_STRUCTURE_TYPE_SAMPLER_NATIVE_PROPERTIES, nullptr, false}; UUR_ASSERT_SUCCESS_OR_UNSUPPORTED(urSamplerCreateWithNativeHandle( native_sampler, context, &props, &hSampler)); ASSERT_NE(hSampler, nullptr);