feature: Add support for importing OpaqueFd external semaphore

Related-To: NEO-14676

Signed-off-by: Raiyan Latif <raiyan.latif@intel.com>
This commit is contained in:
Raiyan Latif 2025-05-13 16:44:10 +00:00 committed by Compute-Runtime-Automation
parent 145c11e9de
commit 0e0cf3f742
12 changed files with 169 additions and 4 deletions

View File

@ -202,6 +202,13 @@ struct PrimeHandle {
int32_t fileDescriptor;
};
struct SyncObjHandle {
uint32_t handle;
uint32_t flags;
int32_t fd;
uint32_t pad;
};
struct PrimaryContextHandle {
uint32_t handle;
int32_t fd;
@ -271,6 +278,7 @@ enum class DrmIoctl {
gemClose,
primeFdToHandle,
primeHandleToFd,
syncObjFdToHandle,
gemVmBind,
gemVmUnbind,
gemWaitUserFence,

View File

@ -5,12 +5,71 @@
*
*/
#include "shared/source/os_interface/linux/external_semaphore_linux.h"
#include "shared/source/os_interface/external_semaphore.h"
#include "shared/source/os_interface/linux/drm_neo.h"
#include "shared/source/os_interface/linux/drm_wrappers.h"
#include "shared/source/os_interface/linux/ioctl_helper.h"
namespace NEO {
std::unique_ptr<ExternalSemaphore> ExternalSemaphore::create(OSInterface *osInterface, ExternalSemaphore::Type type, void *handle, int fd, const char *name) {
return nullptr;
if (!osInterface) {
return nullptr;
}
auto externalSemaphore = ExternalSemaphoreLinux::create(osInterface);
bool result = externalSemaphore->importSemaphore(nullptr, fd, 0, nullptr, type, false);
if (result == false) {
return nullptr;
}
return externalSemaphore;
}
std::unique_ptr<ExternalSemaphoreLinux> ExternalSemaphoreLinux::create(OSInterface *osInterface) {
auto externalSemaphoreLinux = std::make_unique<ExternalSemaphoreLinux>();
externalSemaphoreLinux->osInterface = osInterface;
externalSemaphoreLinux->state = SemaphoreState::Initial;
return externalSemaphoreLinux;
}
bool ExternalSemaphoreLinux::importSemaphore(void *extHandle, int fd, uint32_t flags, const char *name, Type type, bool isNative) {
switch (type) {
case ExternalSemaphore::OpaqueFd:
break;
default:
DEBUG_BREAK_IF(true);
return false;
}
auto drm = this->osInterface->getDriverModel()->as<Drm>();
struct SyncObjHandle args = {};
args.fd = fd;
args.handle = 0;
auto ioctlHelper = drm->getIoctlHelper();
int ret = ioctlHelper->ioctl(DrmIoctl::syncObjFdToHandle, &args);
if (ret != 0) {
return false;
}
this->syncHandle = args.handle;
return true;
}
bool ExternalSemaphoreLinux::enqueueWait(uint64_t *fenceValue) {
return false;
}
bool ExternalSemaphoreLinux::enqueueSignal(uint64_t *fenceValue) {
return false;
}
} // namespace NEO

View File

@ -0,0 +1,36 @@
/*
* Copyright (C) 2025 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#pragma once
#include "shared/source/device/device.h"
#include "shared/source/helpers/debug_helpers.h"
#include "shared/source/helpers/non_copyable_or_moveable.h"
#include "shared/source/os_interface/external_semaphore.h"
#include "shared/source/os_interface/os_interface.h"
#include <limits>
#include <memory>
#include <string>
namespace NEO {
class ExternalSemaphoreLinux : public ExternalSemaphore {
public:
static std::unique_ptr<ExternalSemaphoreLinux> create(OSInterface *osInterface);
~ExternalSemaphoreLinux() override{};
bool importSemaphore(void *extHandle, int fd, uint32_t flags, const char *name, Type type, bool isNative) override;
bool enqueueWait(uint64_t *fenceValue) override;
bool enqueueSignal(uint64_t *fenceValue) override;
protected:
uint32_t syncHandle;
};
} // namespace NEO

View File

@ -94,6 +94,8 @@ unsigned int IoctlHelper::getIoctlRequestValueBase(DrmIoctl ioctlRequest) const
return DRM_IOCTL_PRIME_FD_TO_HANDLE;
case DrmIoctl::primeHandleToFd:
return DRM_IOCTL_PRIME_HANDLE_TO_FD;
case DrmIoctl::syncObjFdToHandle:
return DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE;
default:
UNRECOVERABLE_IF(true);
return 0u;
@ -108,6 +110,8 @@ std::string IoctlHelper::getIoctlStringBase(DrmIoctl ioctlRequest) const {
return "DRM_IOCTL_PRIME_FD_TO_HANDLE";
case DrmIoctl::primeHandleToFd:
return "DRM_IOCTL_PRIME_HANDLE_TO_FD";
case DrmIoctl::syncObjFdToHandle:
return "DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE";
default:
UNRECOVERABLE_IF(true);
return "";

View File

@ -1790,6 +1790,8 @@ unsigned int IoctlHelperXe::getIoctlRequestValue(DrmIoctl ioctlRequest) const {
RETURN_ME(DRM_IOCTL_PRIME_FD_TO_HANDLE);
case DrmIoctl::primeHandleToFd:
RETURN_ME(DRM_IOCTL_PRIME_HANDLE_TO_FD);
case DrmIoctl::syncObjFdToHandle:
RETURN_ME(DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE);
case DrmIoctl::getResetStats:
RETURN_ME(DRM_IOCTL_XE_EXEC_QUEUE_GET_PROPERTY);
case DrmIoctl::debuggerOpen:
@ -1839,6 +1841,8 @@ std::string IoctlHelperXe::getIoctlString(DrmIoctl ioctlRequest) const {
STRINGIFY_ME(DRM_IOCTL_PRIME_FD_TO_HANDLE);
case DrmIoctl::primeHandleToFd:
STRINGIFY_ME(DRM_IOCTL_PRIME_HANDLE_TO_FD);
case DrmIoctl::syncObjFdToHandle:
STRINGIFY_ME(DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE);
case DrmIoctl::debuggerOpen:
STRINGIFY_ME(DRM_IOCTL_XE_EUDEBUG_CONNECT);
case DrmIoctl::metadataCreate:

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2024 Intel Corporation
* Copyright (C) 2021-2025 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
@ -140,6 +140,12 @@ int DrmMockCustom::ioctl(DrmIoctl request, void *arg) {
return -1;
}
} break;
case DrmIoctl::syncObjFdToHandle: {
ioctlCnt.syncObjFdToHandle++;
if (failOnSyncObjFdToHandle == true) {
return -1;
}
} break;
case DrmIoctl::gemSetDomain: {
auto setDomainParams = static_cast<NEO::GemSetDomain *>(arg);
setDomainHandle = setDomainParams->handle;

View File

@ -45,6 +45,7 @@ class Ioctls {
std::atomic<int32_t> gemVmDestroy;
std::atomic<int32_t> primeFdToHandle;
std::atomic<int32_t> handleToPrimeFd;
std::atomic<int32_t> syncObjFdToHandle;
std::atomic<int32_t> gemMmapOffset;
std::atomic<int32_t> gemSetDomain;
std::atomic<int32_t> gemWait;
@ -276,6 +277,7 @@ struct DrmMockCustom : public Drm {
bool failOnPrimeFdToHandle = false;
bool failOnSecondPrimeFdToHandle = false;
bool failOnPrimeHandleToFd = false;
bool failOnSyncObjFdToHandle = false;
// DRM_IOCTL_I915_GEM_CREATE_EXT
uint64_t createExtSize = 0;

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2024 Intel Corporation
* Copyright (C) 2021-2025 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
@ -124,6 +124,7 @@ DG1TEST_F(IoctlHelperTestsDg1, whenGettingIoctlRequestStringThenProperStringIsRe
EXPECT_STREQ(ioctlHelper.getIoctlString(DrmIoctl::query).c_str(), "DRM_IOCTL_I915_QUERY");
EXPECT_STREQ(ioctlHelper.getIoctlString(DrmIoctl::primeFdToHandle).c_str(), "DRM_IOCTL_PRIME_FD_TO_HANDLE");
EXPECT_STREQ(ioctlHelper.getIoctlString(DrmIoctl::primeHandleToFd).c_str(), "DRM_IOCTL_PRIME_HANDLE_TO_FD");
EXPECT_STREQ(ioctlHelper.getIoctlString(DrmIoctl::syncObjFdToHandle).c_str(), "DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE");
EXPECT_STREQ(ioctlHelper.getIoctlString(DrmIoctl::gemContextCreateExt).c_str(), "DRM_IOCTL_I915_GEM_CONTEXT_CREATE_EXT");
EXPECT_STREQ(ioctlHelper.getIoctlString(DrmIoctl::gemMmapOffset).c_str(), "DRM_IOCTL_I915_GEM_MMAP_OFFSET");
EXPECT_STREQ(ioctlHelper.getIoctlString(DrmIoctl::gemVmCreate).c_str(), "DRM_IOCTL_I915_GEM_VM_CREATE");
@ -152,6 +153,7 @@ DG1TEST_F(IoctlHelperTestsDg1, whenGettingIoctlRequestValueThenPropertValueIsRet
EXPECT_EQ(ioctlHelper.getIoctlRequestValue(DrmIoctl::query), static_cast<unsigned int>(DRM_IOCTL_I915_QUERY));
EXPECT_EQ(ioctlHelper.getIoctlRequestValue(DrmIoctl::primeFdToHandle), static_cast<unsigned int>(DRM_IOCTL_PRIME_FD_TO_HANDLE));
EXPECT_EQ(ioctlHelper.getIoctlRequestValue(DrmIoctl::primeHandleToFd), static_cast<unsigned int>(DRM_IOCTL_PRIME_HANDLE_TO_FD));
EXPECT_EQ(ioctlHelper.getIoctlRequestValue(DrmIoctl::syncObjFdToHandle), static_cast<unsigned int>(DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE));
EXPECT_EQ(ioctlHelper.getIoctlRequestValue(DrmIoctl::gemContextCreateExt), static_cast<unsigned int>(DRM_IOCTL_I915_GEM_CONTEXT_CREATE_EXT));
EXPECT_EQ(ioctlHelper.getIoctlRequestValue(DrmIoctl::gemMmapOffset), static_cast<unsigned int>(DRM_IOCTL_I915_GEM_MMAP_OFFSET));
EXPECT_EQ(ioctlHelper.getIoctlRequestValue(DrmIoctl::gemVmCreate), static_cast<unsigned int>(DRM_IOCTL_I915_GEM_VM_CREATE));

View File

@ -73,6 +73,7 @@ TEST_F(IoctlPrelimHelperTests, whenGettingIoctlRequestValueThenPropertValueIsRet
EXPECT_EQ(ioctlHelper.getIoctlRequestValue(DrmIoctl::query), static_cast<unsigned int>(DRM_IOCTL_I915_QUERY));
EXPECT_EQ(ioctlHelper.getIoctlRequestValue(DrmIoctl::primeFdToHandle), static_cast<unsigned int>(DRM_IOCTL_PRIME_FD_TO_HANDLE));
EXPECT_EQ(ioctlHelper.getIoctlRequestValue(DrmIoctl::primeHandleToFd), static_cast<unsigned int>(DRM_IOCTL_PRIME_HANDLE_TO_FD));
EXPECT_EQ(ioctlHelper.getIoctlRequestValue(DrmIoctl::syncObjFdToHandle), static_cast<unsigned int>(DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE));
EXPECT_EQ(ioctlHelper.getIoctlRequestValue(DrmIoctl::gemVmBind), static_cast<unsigned int>(PRELIM_DRM_IOCTL_I915_GEM_VM_BIND));
EXPECT_EQ(ioctlHelper.getIoctlRequestValue(DrmIoctl::gemVmUnbind), static_cast<unsigned int>(PRELIM_DRM_IOCTL_I915_GEM_VM_UNBIND));
EXPECT_EQ(ioctlHelper.getIoctlRequestValue(DrmIoctl::gemWaitUserFence), static_cast<unsigned int>(PRELIM_DRM_IOCTL_I915_GEM_WAIT_USER_FENCE));
@ -125,6 +126,7 @@ TEST_F(IoctlPrelimHelperTests, whenGettingIoctlRequestStringThenProperStringIsRe
EXPECT_STREQ(ioctlHelper.getIoctlString(DrmIoctl::query).c_str(), "DRM_IOCTL_I915_QUERY");
EXPECT_STREQ(ioctlHelper.getIoctlString(DrmIoctl::primeFdToHandle).c_str(), "DRM_IOCTL_PRIME_FD_TO_HANDLE");
EXPECT_STREQ(ioctlHelper.getIoctlString(DrmIoctl::primeHandleToFd).c_str(), "DRM_IOCTL_PRIME_HANDLE_TO_FD");
EXPECT_STREQ(ioctlHelper.getIoctlString(DrmIoctl::syncObjFdToHandle).c_str(), "DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE");
EXPECT_STREQ(ioctlHelper.getIoctlString(DrmIoctl::gemVmBind).c_str(), "PRELIM_DRM_IOCTL_I915_GEM_VM_BIND");
EXPECT_STREQ(ioctlHelper.getIoctlString(DrmIoctl::gemVmUnbind).c_str(), "PRELIM_DRM_IOCTL_I915_GEM_VM_UNBIND");
EXPECT_STREQ(ioctlHelper.getIoctlString(DrmIoctl::gemWaitUserFence).c_str(), "PRELIM_DRM_IOCTL_I915_GEM_WAIT_USER_FENCE");

View File

@ -178,6 +178,7 @@ TEST(IoctlHelperUpstreamTest, whenGettingIoctlRequestStringThenProperStringIsRet
EXPECT_STREQ(ioctlHelper.getIoctlString(DrmIoctl::query).c_str(), "DRM_IOCTL_I915_QUERY");
EXPECT_STREQ(ioctlHelper.getIoctlString(DrmIoctl::primeFdToHandle).c_str(), "DRM_IOCTL_PRIME_FD_TO_HANDLE");
EXPECT_STREQ(ioctlHelper.getIoctlString(DrmIoctl::primeHandleToFd).c_str(), "DRM_IOCTL_PRIME_HANDLE_TO_FD");
EXPECT_STREQ(ioctlHelper.getIoctlString(DrmIoctl::syncObjFdToHandle).c_str(), "DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE");
EXPECT_STREQ(ioctlHelper.getIoctlString(DrmIoctl::gemCreateExt).c_str(), "DRM_IOCTL_I915_GEM_CREATE_EXT");
EXPECT_STREQ(ioctlHelper.getIoctlString(DrmIoctl::gemMmapOffset).c_str(), "DRM_IOCTL_I915_GEM_MMAP_OFFSET");
EXPECT_STREQ(ioctlHelper.getIoctlString(DrmIoctl::gemVmCreate).c_str(), "DRM_IOCTL_I915_GEM_VM_CREATE");
@ -211,6 +212,7 @@ TEST(IoctlHelperUpstreamTest, whenGettingIoctlRequestValueThenProperValueIsRetur
EXPECT_EQ(ioctlHelper.getIoctlRequestValue(DrmIoctl::query), static_cast<unsigned int>(DRM_IOCTL_I915_QUERY));
EXPECT_EQ(ioctlHelper.getIoctlRequestValue(DrmIoctl::primeFdToHandle), static_cast<unsigned int>(DRM_IOCTL_PRIME_FD_TO_HANDLE));
EXPECT_EQ(ioctlHelper.getIoctlRequestValue(DrmIoctl::primeHandleToFd), static_cast<unsigned int>(DRM_IOCTL_PRIME_HANDLE_TO_FD));
EXPECT_EQ(ioctlHelper.getIoctlRequestValue(DrmIoctl::syncObjFdToHandle), static_cast<unsigned int>(DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE));
EXPECT_EQ(ioctlHelper.getIoctlRequestValue(DrmIoctl::gemCreateExt), static_cast<unsigned int>(DRM_IOCTL_I915_GEM_CREATE_EXT));
EXPECT_EQ(ioctlHelper.getIoctlRequestValue(DrmIoctl::gemMmapOffset), static_cast<unsigned int>(DRM_IOCTL_I915_GEM_MMAP_OFFSET));
EXPECT_EQ(ioctlHelper.getIoctlRequestValue(DrmIoctl::gemVmCreate), static_cast<unsigned int>(DRM_IOCTL_I915_GEM_VM_CREATE));

View File

@ -522,6 +522,7 @@ TEST_F(IoctlHelperXeTest, givenIoctlHelperXeWhenCallingAnyMethodThenDummyValueIs
verifyIoctlString(DrmIoctl::gemWaitUserFence, "DRM_IOCTL_XE_WAIT_USER_FENCE");
verifyIoctlString(DrmIoctl::primeFdToHandle, "DRM_IOCTL_PRIME_FD_TO_HANDLE");
verifyIoctlString(DrmIoctl::primeHandleToFd, "DRM_IOCTL_PRIME_HANDLE_TO_FD");
verifyIoctlString(DrmIoctl::syncObjFdToHandle, "DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE");
verifyIoctlString(DrmIoctl::getResetStats, "DRM_IOCTL_XE_EXEC_QUEUE_GET_PROPERTY");
EXPECT_TRUE(xeIoctlHelper->completionFenceExtensionSupported(true));
@ -583,6 +584,7 @@ TEST_F(IoctlHelperXeTest, whenGettingIoctlRequestValueThenPropertValueIsReturned
verifyIoctlRequestValue(DRM_IOCTL_XE_EXEC_QUEUE_DESTROY, DrmIoctl::gemContextDestroy);
verifyIoctlRequestValue(DRM_IOCTL_PRIME_FD_TO_HANDLE, DrmIoctl::primeFdToHandle);
verifyIoctlRequestValue(DRM_IOCTL_PRIME_HANDLE_TO_FD, DrmIoctl::primeHandleToFd);
verifyIoctlRequestValue(DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, DrmIoctl::syncObjFdToHandle);
}
TEST_F(IoctlHelperXeTest, verifyPublicFunctions) {

View File

@ -16,11 +16,49 @@
namespace NEO {
using DrmExternalSemaphoreTest = Test<DrmMemoryManagerFixture>;
using DrmExternalSemaphoreTest = Test<DrmMemoryManagerFixtureWithoutQuietIoctlExpectation>;
TEST_F(DrmExternalSemaphoreTest, givenNullOsInterfaceWhenCreateExternalSemaphoreIsCalledThenNullptrIsReturned) {
auto externalSemaphore = ExternalSemaphore::create(nullptr, ExternalSemaphore::Type::OpaqueFd, nullptr, 0u, nullptr);
EXPECT_EQ(externalSemaphore, nullptr);
}
TEST_F(DrmExternalSemaphoreTest, givenInvalidLinuxSemaphoreTypeWhenCreateExternalSemaphoreIsCalledThenNullptrIsReturned) {
auto externalSemaphore = ExternalSemaphore::create(executionEnvironment->rootDeviceEnvironments[0]->osInterface.get(), ExternalSemaphore::Type::OpaqueWin32, nullptr, 0u, nullptr);
EXPECT_EQ(externalSemaphore, nullptr);
}
TEST_F(DrmExternalSemaphoreTest, givenOpaqueFdSemaphoreTypeWhenCreateExternalSemaphoreIsCalledThenNonNullptrIsReturned) {
auto externalSemaphore = ExternalSemaphore::create(executionEnvironment->rootDeviceEnvironments[0]->osInterface.get(), ExternalSemaphore::Type::OpaqueFd, nullptr, 0u, nullptr);
EXPECT_NE(externalSemaphore, nullptr);
}
TEST_F(DrmExternalSemaphoreTest, givenIoctlFailsWhenCreateExternalSemaphoreIsCalledThenNullptrIsReturned) {
auto mockDrm = static_cast<DrmMockCustom *>(executionEnvironment->rootDeviceEnvironments[0]->osInterface->getDriverModel()->as<Drm>());
mockDrm->failOnSyncObjFdToHandle = true;
EXPECT_EQ(mockDrm->ioctlCnt.syncObjFdToHandle, 0);
auto externalSemaphore = ExternalSemaphore::create(executionEnvironment->rootDeviceEnvironments[0]->osInterface.get(), ExternalSemaphore::Type::OpaqueFd, nullptr, 0u, nullptr);
EXPECT_EQ(externalSemaphore, nullptr);
EXPECT_EQ(mockDrm->ioctlCnt.syncObjFdToHandle, 1);
}
TEST_F(DrmExternalSemaphoreTest, givenOpaqueFdSemaphoreWhenEnqueueSignalIsCalledThenFalseIsReturned) {
auto externalSemaphore = ExternalSemaphore::create(executionEnvironment->rootDeviceEnvironments[0]->osInterface.get(), ExternalSemaphore::Type::OpaqueFd, nullptr, 0u, nullptr);
EXPECT_NE(externalSemaphore, nullptr);
uint64_t fenceValue = 1u;
auto result = externalSemaphore->enqueueSignal(&fenceValue);
EXPECT_EQ(result, false);
}
TEST_F(DrmExternalSemaphoreTest, givenOpaqueFdSemaphoreWhenEnqueueWaitIsCalledThenFalseIsReturned) {
auto externalSemaphore = ExternalSemaphore::create(executionEnvironment->rootDeviceEnvironments[0]->osInterface.get(), ExternalSemaphore::Type::OpaqueFd, nullptr, 0u, nullptr);
EXPECT_NE(externalSemaphore, nullptr);
uint64_t fenceValue = 1u;
auto result = externalSemaphore->enqueueWait(&fenceValue);
EXPECT_EQ(result, false);
}
} // namespace NEO