Skip to content

Commit

Permalink
[L0] Add Support for External Semaphores
Browse files Browse the repository at this point in the history
- Added support for using the Intel L0 experimental extension for
  external sempahores.

Signed-off-by: Neil R. Spruit <[email protected]>
  • Loading branch information
nrspruit committed Nov 22, 2024
1 parent e9d94b1 commit cd07eb2
Show file tree
Hide file tree
Showing 4 changed files with 294 additions and 27 deletions.
73 changes: 73 additions & 0 deletions source/adapters/level_zero/common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -531,3 +531,76 @@ extern thread_local int32_t ErrorAdapterNativeCode;
int32_t AdapterErrorCode);

#define L0_DRIVER_INORDER_MIN_VERSION 29534

// Definitions for the External Semaphore Extension

#ifndef ZE_INTEL_EXTERNAL_SEMAPHORE_EXP_NAME
/// @brief Event sync mode extension name
#define ZE_INTEL_EXTERNAL_SEMAPHORE_EXP_NAME \
"ZE_intel_experimental_external_semaphore"
#endif // ZE_INTEL_EXTERNAL_SEMAPHORE_EXP_NAME

typedef enum _ze_intel_external_semaphore_exp_version_t {
ZE_EXTERNAL_SEMAPHORE_EXP_VERSION_1_0 =
ZE_MAKE_VERSION(1, 0), ///< version 1.0
ZE_EXTERNAL_SEMAPHORE_EXP_VERSION_CURRENT =
ZE_MAKE_VERSION(1, 0), ///< latest known version
ZE_EXTERNAL_SEMAPHORE_EXP_VERSION_FORCE_UINT32 = 0x7fffffff
} ze_intel_external_semaphore_exp_version_t;
typedef enum _ze_intel_external_semaphore_exp_flags_t {
ZE_EXTERNAL_SEMAPHORE_EXP_FLAGS_OPAQUE_FD,
ZE_EXTERNAL_SEMAPHORE_EXP_FLAGS_OPAQUE_WIN32,
ZE_EXTERNAL_SEMAPHORE_EXP_FLAGS_OPAQUE_WIN32_KMT,
ZE_EXTERNAL_SEMAPHORE_EXP_FLAGS_D3D12_FENCE,
ZE_EXTERNAL_SEMAPHORE_EXP_FLAGS_D3D11_FENCE,
ZE_EXTERNAL_SEMAPHORE_EXP_FLAGS_KEYED_MUTEX,
ZE_EXTERNAL_SEMAPHORE_EXP_FLAGS_KEYED_MUTEX_KMT,
ZE_EXTERNAL_SEMAPHORE_EXP_FLAGS_TIMELINE_SEMAPHORE_FD,
ZE_EXTERNAL_SEMAPHORE_EXP_FLAGS_TIMELINE_SEMAPHORE_WIN32
} ze_intel_external_semaphore_exp_flags_t;

typedef struct _ze_intel_external_semaphore_exp_desc_t {
ze_structure_type_t stype;
const void *pNext;
ze_intel_external_semaphore_exp_flags_t flags;
} ze_intel_external_semaphore_exp_desc_t;

typedef struct _ze_intel_external_semaphore_win32_exp_desc_t {
ze_structure_type_t stype;
const void *pNext;
void *handle;
const char *name;
} ze_intel_external_semaphore_win32_exp_desc_t;

typedef struct _ze_intel_external_semaphore_fd_exp_desc_t {
ze_structure_type_t stype;
const void *pNext;
int fd;
} ze_intel_external_semaphore_desc_fd_exp_desc_t;

typedef struct _ze_intel_external_semaphore_signal_exp_params_t {
ze_structure_type_t stype;
const void *pNext;
uint64_t value;
} ze_intel_external_semaphore_signal_exp_params_t;

typedef struct _ze_intel_external_semaphore_wait_exp_params_t {
ze_structure_type_t stype;
const void *pNext;

uint64_t value;
} ze_intel_external_semaphore_wait_exp_params_t;

typedef struct _ze_intel_external_semaphore_exp_handle_t
*ze_intel_external_semaphore_exp_handle_t;

#define ZE_INTEL_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_EXP_DESC \
(ze_structure_type_t)0x0003001E
#define ZE_INTEL_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_WIN32_EXP_DESC \
(ze_structure_type_t)0x0003001F
#define ZE_INTEL_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_FD_EXP_DESC \
(ze_structure_type_t)0x00030023
#define ZE_INTEL_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_SIGNAL_PARAMS_EXP \
(ze_structure_type_t)0x00030024
#define ZE_INTEL_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_WAIT_PARAMS_EXP \
(ze_structure_type_t)0x00030025
188 changes: 162 additions & 26 deletions source/adapters/level_zero/image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1190,41 +1190,130 @@ ur_result_t urBindlessImagesImportExternalSemaphoreExp(
ur_exp_external_semaphore_type_t semHandleType,
ur_exp_external_semaphore_desc_t *pExternalSemaphoreDesc,
ur_exp_external_semaphore_handle_t *phExternalSemaphoreHandle) {
std::ignore = hContext;
std::ignore = hDevice;
std::ignore = semHandleType;
std::ignore = pExternalSemaphoreDesc;
std::ignore = phExternalSemaphoreHandle;
logger::error(logger::LegacyMessage("[UR][L0] {} function not implemented!"),
"{} function not implemented!", __FUNCTION__);
return UR_RESULT_ERROR_UNSUPPORTED_FEATURE;

auto UrPlatform = hContext->getPlatform();
if (UrPlatform->ZeExternalSemaphoreExt.Supported == false) {
logger::error(logger::LegacyMessage("[UR][L0] "),
" {} function not supported!", __FUNCTION__);
return UR_RESULT_ERROR_UNSUPPORTED_FEATURE;
}
ze_intel_external_semaphore_exp_desc_t SemDesc = {
ZE_INTEL_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_EXP_DESC, nullptr,
ZE_EXTERNAL_SEMAPHORE_EXP_FLAGS_OPAQUE_FD};
ze_intel_external_semaphore_exp_handle_t ExtSemaphoreHandle;
ze_intel_external_semaphore_desc_fd_exp_desc_t FDExpDesc = {
ZE_INTEL_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_FD_EXP_DESC, nullptr, 0};
_ze_intel_external_semaphore_win32_exp_desc_t Win32ExpDesc = {
ZE_INTEL_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_WIN32_EXP_DESC, nullptr,
nullptr, nullptr};
void *pNext = const_cast<void *>(pExternalSemaphoreDesc->pNext);
while (pNext != nullptr) {
const ur_base_desc_t *BaseDesc = static_cast<const ur_base_desc_t *>(pNext);
if (BaseDesc->stype == UR_STRUCTURE_TYPE_EXP_FILE_DESCRIPTOR) {
auto FileDescriptor =
static_cast<const ur_exp_file_descriptor_t *>(pNext);
FDExpDesc.fd = FileDescriptor->fd;
SemDesc.pNext = &FDExpDesc;
SemDesc.flags = ZE_EXTERNAL_SEMAPHORE_EXP_FLAGS_OPAQUE_FD;
} else if (BaseDesc->stype == UR_STRUCTURE_TYPE_EXP_WIN32_HANDLE) {
SemDesc.pNext = &Win32ExpDesc;
auto Win32Handle = static_cast<const ur_exp_win32_handle_t *>(pNext);
switch (semHandleType) {
case UR_EXP_EXTERNAL_SEMAPHORE_TYPE_WIN32_NT:
SemDesc.flags = ZE_EXTERNAL_SEMAPHORE_EXP_FLAGS_OPAQUE_WIN32;
break;
case UR_EXP_EXTERNAL_SEMAPHORE_TYPE_WIN32_NT_DX12_FENCE:
SemDesc.flags = ZE_EXTERNAL_SEMAPHORE_EXP_FLAGS_D3D12_FENCE;
break;
case UR_EXP_EXTERNAL_SEMAPHORE_TYPE_OPAQUE_FD:
SemDesc.flags = ZE_EXTERNAL_SEMAPHORE_EXP_FLAGS_OPAQUE_FD;
break;
default:
return UR_RESULT_ERROR_INVALID_VALUE;
}
Win32ExpDesc.handle = Win32Handle->handle;
}
pNext = const_cast<void *>(BaseDesc->pNext);
}

ZE2UR_CALL(UrPlatform->ZeExternalSemaphoreExt.zexImportExternalSemaphoreExp,
(hDevice->ZeDevice, &ExtSemaphoreHandle, &SemDesc));
*phExternalSemaphoreHandle =
(ur_exp_external_semaphore_handle_t)ExtSemaphoreHandle;

return UR_RESULT_SUCCESS;
}

ur_result_t urBindlessImagesReleaseExternalSemaphoreExp(
ur_context_handle_t hContext, ur_device_handle_t hDevice,
ur_exp_external_semaphore_handle_t hExternalSemaphore) {
std::ignore = hContext;
std::ignore = hDevice;
std::ignore = hExternalSemaphore;
logger::error(logger::LegacyMessage("[UR][L0] {} function not implemented!"),
"{} function not implemented!", __FUNCTION__);
return UR_RESULT_ERROR_UNSUPPORTED_FEATURE;
auto UrPlatform = hContext->getPlatform();
if (UrPlatform->ZeExternalSemaphoreExt.Supported == false) {
logger::error(logger::LegacyMessage("[UR][L0] "),
" {} function not supported!", __FUNCTION__);
return UR_RESULT_ERROR_UNSUPPORTED_FEATURE;
}
ZE2UR_CALL(
UrPlatform->ZeExternalSemaphoreExt.zexDeviceReleaseExternalSemaphoreExp,
((ze_intel_external_semaphore_exp_handle_t)hExternalSemaphore));

return UR_RESULT_SUCCESS;
}

ur_result_t urBindlessImagesWaitExternalSemaphoreExp(
ur_queue_handle_t hQueue, ur_exp_external_semaphore_handle_t hSemaphore,
bool hasValue, uint64_t waitValue, uint32_t numEventsInWaitList,
const ur_event_handle_t *phEventWaitList, ur_event_handle_t *phEvent) {
std::ignore = hQueue;
std::ignore = hSemaphore;
std::ignore = hasValue;
std::ignore = waitValue;
std::ignore = numEventsInWaitList;
std::ignore = phEventWaitList;
std::ignore = phEvent;
logger::error(logger::LegacyMessage("[UR][L0] "),
" {} function not implemented!", __FUNCTION__);
return UR_RESULT_ERROR_UNSUPPORTED_FEATURE;
auto UrPlatform = hQueue->Context->getPlatform();
if (UrPlatform->ZeExternalSemaphoreExt.Supported == false) {
logger::error(logger::LegacyMessage("[UR][L0] "),
" {} function not supported!", __FUNCTION__);
return UR_RESULT_ERROR_UNSUPPORTED_FEATURE;
}

bool UseCopyEngine = false;

// We want to batch these commands to avoid extra submissions (costly)
bool OkToBatch = true;

_ur_ze_event_list_t TmpWaitList;
UR_CALL(TmpWaitList.createAndRetainUrZeEventList(
numEventsInWaitList, phEventWaitList, hQueue, UseCopyEngine));

// Get a new command list to be used on this call
ur_command_list_ptr_t CommandList{};
UR_CALL(hQueue->Context->getAvailableCommandList(
hQueue, CommandList, UseCopyEngine, numEventsInWaitList, phEventWaitList,
OkToBatch, nullptr /*ForcedCmdQueue*/));

ze_event_handle_t ZeEvent = nullptr;
ur_event_handle_t InternalEvent;
bool IsInternal = phEvent == nullptr;
ur_event_handle_t *Event = phEvent ? phEvent : &InternalEvent;
UR_CALL(createEventAndAssociateQueue(hQueue, Event,
UR_COMMAND_EXTERNAL_SEMAPHORE_WAIT_EXP,
CommandList, IsInternal,
/*IsMultiDevice*/ false));
UR_CALL(setSignalEvent(hQueue, UseCopyEngine, &ZeEvent, Event,
numEventsInWaitList, phEventWaitList,
CommandList->second.ZeQueue));
(*Event)->WaitList = TmpWaitList;

const auto &ZeCommandList = CommandList->first;
const auto &WaitList = (*Event)->WaitList;

ze_intel_external_semaphore_wait_exp_params_t WaitParams = {
ZE_INTEL_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_WAIT_PARAMS_EXP, nullptr, 0};
WaitParams.value = hasValue ? waitValue : 0;
const ze_intel_external_semaphore_exp_handle_t hExtSemaphore =
reinterpret_cast<ze_intel_external_semaphore_exp_handle_t>(hSemaphore);
ZE2UR_CALL(UrPlatform->ZeExternalSemaphoreExt
.zexCommandListAppendWaitExternalSemaphoresExp,
(ZeCommandList, &hExtSemaphore, &WaitParams, 1, ZeEvent,
WaitList.Length, WaitList.ZeEventList));

return UR_RESULT_SUCCESS;
}

ur_result_t urBindlessImagesSignalExternalSemaphoreExp(
Expand All @@ -1238,9 +1327,56 @@ ur_result_t urBindlessImagesSignalExternalSemaphoreExp(
std::ignore = numEventsInWaitList;
std::ignore = phEventWaitList;
std::ignore = phEvent;
logger::error(logger::LegacyMessage("[UR][L0] {} function not implemented!"),
"{} function not implemented!", __FUNCTION__);
return UR_RESULT_ERROR_UNSUPPORTED_FEATURE;
auto UrPlatform = hQueue->Context->getPlatform();
if (UrPlatform->ZeExternalSemaphoreExt.Supported == false) {
logger::error(logger::LegacyMessage("[UR][L0] "),
" {} function not supported!", __FUNCTION__);
return UR_RESULT_ERROR_UNSUPPORTED_FEATURE;
}

bool UseCopyEngine = false;

// We want to batch these commands to avoid extra submissions (costly)
bool OkToBatch = true;

_ur_ze_event_list_t TmpWaitList;
UR_CALL(TmpWaitList.createAndRetainUrZeEventList(
numEventsInWaitList, phEventWaitList, hQueue, UseCopyEngine));

// Get a new command list to be used on this call
ur_command_list_ptr_t CommandList{};
UR_CALL(hQueue->Context->getAvailableCommandList(
hQueue, CommandList, UseCopyEngine, numEventsInWaitList, phEventWaitList,
OkToBatch, nullptr /*ForcedCmdQueue*/));

ze_event_handle_t ZeEvent = nullptr;
ur_event_handle_t InternalEvent;
bool IsInternal = phEvent == nullptr;
ur_event_handle_t *Event = phEvent ? phEvent : &InternalEvent;
UR_CALL(createEventAndAssociateQueue(hQueue, Event,
UR_COMMAND_EXTERNAL_SEMAPHORE_SIGNAL_EXP,
CommandList, IsInternal,
/*IsMultiDevice*/ false));
UR_CALL(setSignalEvent(hQueue, UseCopyEngine, &ZeEvent, Event,
numEventsInWaitList, phEventWaitList,
CommandList->second.ZeQueue));
(*Event)->WaitList = TmpWaitList;

const auto &ZeCommandList = CommandList->first;
const auto &WaitList = (*Event)->WaitList;

ze_intel_external_semaphore_signal_exp_params_t SignalParams = {
ZE_INTEL_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_SIGNAL_PARAMS_EXP, nullptr, 0};
SignalParams.value = hasValue ? signalValue : 0;
const ze_intel_external_semaphore_exp_handle_t hExtSemaphore =
reinterpret_cast<ze_intel_external_semaphore_exp_handle_t>(hSemaphore);

ZE2UR_CALL(UrPlatform->ZeExternalSemaphoreExt
.zexCommandListAppendSignalExternalSemaphoresExp,
(ZeCommandList, &hExtSemaphore, &SignalParams, 1, ZeEvent,
WaitList.Length, WaitList.ZeEventList));

return UR_RESULT_SUCCESS;
}

} // namespace ur::level_zero
38 changes: 38 additions & 0 deletions source/adapters/level_zero/platform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ ur_result_t ur_platform_handle_t_::initialize() {
ZE2UR_CALL(zeDriverGetExtensionProperties,
(ZeDriver, &Count, ZeExtensions.data()));

bool ZeIntelExternalSemaphoreExtensionSupported = false;
for (auto &extension : ZeExtensions) {
// Check if global offset extension is available
if (strncmp(extension.name, ZE_GLOBAL_OFFSET_EXP_NAME,
Expand Down Expand Up @@ -251,6 +252,11 @@ ur_result_t ur_platform_handle_t_::initialize() {
if (extension.version ==
ZE_IMMEDIATE_COMMAND_LIST_APPEND_EXP_VERSION_CURRENT) {
zeDriverImmediateCommandListAppendFound = true;
// Check if extension is available for External Sempahores
if (strncmp(extension.name, ZE_INTEL_EXTERNAL_SEMAPHORE_EXP_NAME,
strlen(ZE_INTEL_EXTERNAL_SEMAPHORE_EXP_NAME) + 1) == 0) {
if (extension.version == ZE_EXTERNAL_SEMAPHORE_EXP_VERSION_1_0) {
ZeIntelExternalSemaphoreExtensionSupported = true;
}
}
zeDriverExtensionMap[extension.name] = extension.version;
Expand Down Expand Up @@ -287,6 +293,38 @@ ur_result_t ur_platform_handle_t_::initialize() {
// If yes, then set up L0 API pointers if the platform supports it.
ZeUSMImport.setZeUSMImport(this);

if (ZeIntelExternalSemaphoreExtensionSupported) {
ZeExternalSemaphoreExt.Supported |=
(ZE_CALL_NOCHECK(
zeDriverGetExtensionFunctionAddress,
(ZeDriver, "zeIntelDeviceImportExternalSemaphoreExp",
reinterpret_cast<void **>(
&ZeExternalSemaphoreExt.zexImportExternalSemaphoreExp))) ==
0);
ZeExternalSemaphoreExt.Supported |=
(ZE_CALL_NOCHECK(
zeDriverGetExtensionFunctionAddress,
(ZeDriver, "zeIntelCommandListAppendWaitExternalSemaphoresExp",
reinterpret_cast<void **>(
&ZeExternalSemaphoreExt
.zexCommandListAppendWaitExternalSemaphoresExp))) == 0);
ZeExternalSemaphoreExt.Supported |=
(ZE_CALL_NOCHECK(
zeDriverGetExtensionFunctionAddress,
(ZeDriver, "zeIntelCommandListAppendSignalExternalSemaphoresExp",
reinterpret_cast<void **>(
&ZeExternalSemaphoreExt
.zexCommandListAppendSignalExternalSemaphoresExp))) ==
0);
ZeExternalSemaphoreExt.Supported |=
(ZE_CALL_NOCHECK(zeDriverGetExtensionFunctionAddress,
(ZeDriver, "zeIntelDeviceReleaseExternalSemaphoreExp",
reinterpret_cast<void **>(
&ZeExternalSemaphoreExt
.zexDeviceReleaseExternalSemaphoreExp))) ==
0);
}

// Check if mutable command list extension is supported and initialize
// function pointers.
ZeMutableCmdListExt.Supported |=
Expand Down
22 changes: 21 additions & 1 deletion source/adapters/level_zero/platform.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,24 @@ struct ur_platform_handle_t_ : public _ur_platform {
ze_command_list_handle_t, uint64_t, uint32_t,
ze_event_handle_t *) = nullptr;
} ZeMutableCmdListExt;
};

// Structure with function pointers for External Semaphore Extension.
struct ZeExternalSemaphoreExtension {
bool Supported = false;
ze_result_t (*zexImportExternalSemaphoreExp)(
ze_device_handle_t, ze_intel_external_semaphore_exp_handle_t *,
const ze_intel_external_semaphore_exp_desc_t *);
ze_result_t (*zexCommandListAppendWaitExternalSemaphoresExp)(
ze_command_list_handle_t,
const ze_intel_external_semaphore_exp_handle_t *,
const ze_intel_external_semaphore_wait_exp_params_t *, unsigned int,
ze_event_handle_t, uint32_t, ze_event_handle_t *);
ze_result_t (*zexCommandListAppendSignalExternalSemaphoresExp)(
ze_command_list_handle_t,
const ze_intel_external_semaphore_exp_handle_t *,
const ze_intel_external_semaphore_signal_exp_params_t *, size_t,
ze_event_handle_t, uint32_t, ze_event_handle_t *);
ze_result_t (*zexDeviceReleaseExternalSemaphoreExp)(
ze_intel_external_semaphore_exp_handle_t);
} ZeExternalSemaphoreExt;
};

0 comments on commit cd07eb2

Please sign in to comment.