Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion api/api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -782,7 +782,7 @@ OIDN_API_NAMESPACE_BEGIN
if ((handleType & device->getExternalSemaphoreTypes()) != handleType)
throw Exception(Error::InvalidArgument, "external semaphore type not supported by the device");
if ((!handle && !name) || (handle && name))
throw Exception(Error::InvalidArgument, "exactly one of the external memory handle and name must be non-null");
throw Exception(Error::InvalidArgument, "exactly one of the external semaphore handle and name must be non-null");
Ref<Semaphore> semaphore = device->newExternalSemaphore(handleType, handle, name);
return reinterpret_cast<OIDNSemaphore>(semaphore.detach());
OIDN_CATCH_DEVICE(device)
Expand Down
2 changes: 2 additions & 0 deletions devices/hip/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ set(OIDN_HIP_SOURCES
hip_engine.cpp
hip_external_buffer.h
hip_external_buffer.cpp
hip_external_semaphore.h
hip_external_semaphore.cpp
hip_module.cpp
)

Expand Down
11 changes: 11 additions & 0 deletions devices/hip/hip_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,19 @@ OIDN_NAMESPACE_BEGIN
ExternalMemoryTypeFlag::D3D11ResourceKMT |
ExternalMemoryTypeFlag::D3D12Heap |
ExternalMemoryTypeFlag::D3D12Resource;

externalSemaphoreTypes = ExternalSemaphoreTypeFlag::OpaqueWin32 |
ExternalSemaphoreTypeFlag::OpaqueWin32KMT |
ExternalSemaphoreTypeFlag::D3D11Fence |
ExternalSemaphoreTypeFlag::D3D12Fence |
ExternalSemaphoreTypeFlag::KeyedMutex |
ExternalSemaphoreTypeFlag::KeyedMutexKMT |
ExternalSemaphoreTypeFlag::TimelineSemaphoreWin32;
#else
externalMemoryTypes = ExternalMemoryTypeFlag::OpaqueFD;

// Not yet supported by HIP on Linux.
externalSemaphoreTypes = 0;
#endif

externalMemoryTypes |= ExternalMemoryTypeFlag::Dedicated;
Expand Down
107 changes: 107 additions & 0 deletions devices/hip/hip_engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "hip_engine.h"
#include "hip_external_buffer.h"
#include "hip_external_semaphore.h"
#include "hip_conv.h"
#include "../gpu/gpu_autoexposure.h"
#include "../gpu/gpu_input_process.h"
Expand Down Expand Up @@ -30,6 +31,112 @@ OIDN_NAMESPACE_BEGIN
return makeRef<HIPExternalBuffer>(this, handleType, handle, name, byteSize);
}

Ref<Semaphore> HIPEngine::newExternalSemaphore(ExternalSemaphoreTypeFlags fdType,
int fd)
{
return makeRef<HIPExternalSemaphore>(this, fdType, fd);
}

Ref<Semaphore> HIPEngine::newExternalSemaphore(ExternalSemaphoreTypeFlags handleType,
void* handle, const void* name)
{
return makeRef<HIPExternalSemaphore>(this, handleType, handle, name);
}

void HIPEngine::submitSignalSemaphores(Semaphore* const* semaphores,
const uint64_t* values,
int numSemaphores)
{
if (numSemaphores < 0)
throw Exception(Error::InvalidArgument, "number of semaphores is negative");
if (numSemaphores == 0)
return;
if (semaphores == nullptr)
throw Exception(Error::InvalidArgument, "semaphores pointer is null");

semaphoreHandles.resize(numSemaphores);
semaphoreSignalParams.resize(numSemaphores);

for (int i = 0; i < numSemaphores; ++i)
{
if (semaphores[i] == nullptr)
throw Exception(Error::InvalidArgument, "semaphore is null");
if (semaphores[i]->getDevice() != getDevice())
throw Exception(Error::InvalidArgument, "semaphore was created on a different device");

HIPExternalSemaphore* hipSemaphore = reinterpret_cast<HIPExternalSemaphore*>(semaphores[i]);
ExternalSemaphoreTypeFlags type = hipSemaphore->getType();

semaphoreHandles[i] = hipSemaphore->getHandle();

semaphoreSignalParams[i] = {};
if (values != nullptr)
{
if (type == ExternalSemaphoreTypeFlag::KeyedMutex ||
type == ExternalSemaphoreTypeFlag::KeyedMutexKMT)
semaphoreSignalParams[i].params.keyedMutex.key = values[i];
else
semaphoreSignalParams[i].params.fence.value = values[i];
}
}

checkError(hipSignalExternalSemaphoresAsync(
semaphoreHandles.data(),
semaphoreSignalParams.data(),
numSemaphores,
stream));
}

void HIPEngine::submitWaitSemaphores(Semaphore* const* semaphores,
const uint64_t* values,
const uint32_t* timeoutsMs,
int numSemaphores)
{
if (numSemaphores < 0)
throw Exception(Error::InvalidArgument, "number of semaphores is negative");
if (numSemaphores == 0)
return;
if (semaphores == nullptr)
throw Exception(Error::InvalidArgument, "semaphores pointer is null");

semaphoreHandles.resize(numSemaphores);
semaphoreWaitParams.resize(numSemaphores);

for (int i = 0; i < numSemaphores; ++i)
{
if (semaphores[i] == nullptr)
throw Exception(Error::InvalidArgument, "semaphore is null");
if (semaphores[i]->getDevice() != getDevice())
throw Exception(Error::InvalidArgument, "semaphore was created on a different device");

HIPExternalSemaphore* hipSemaphore = reinterpret_cast<HIPExternalSemaphore*>(semaphores[i]);
ExternalSemaphoreTypeFlags type = hipSemaphore->getType();

semaphoreHandles[i] = hipSemaphore->getHandle();

semaphoreWaitParams[i] = {};
if (type == ExternalSemaphoreTypeFlag::KeyedMutex ||
type == ExternalSemaphoreTypeFlag::KeyedMutexKMT)
{
if (values != nullptr)
semaphoreWaitParams[i].params.keyedMutex.key = values[i];
if (timeoutsMs != nullptr)
semaphoreWaitParams[i].params.keyedMutex.timeoutMs = timeoutsMs[i];
}
else
{
if (values != nullptr)
semaphoreWaitParams[i].params.fence.value = values[i];
}
}

checkError(hipWaitExternalSemaphoresAsync(
semaphoreHandles.data(),
semaphoreWaitParams.data(),
numSemaphores,
stream));
}

bool HIPEngine::isSupported(const TensorDesc& desc) const
{
// CK tensors must be smaller than 2GB
Expand Down
21 changes: 21 additions & 0 deletions devices/hip/hip_engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,22 @@ OIDN_NAMESPACE_BEGIN
// Tensor
bool isSupported(const TensorDesc& desc) const override;

// Semaphore
Ref<Semaphore> newExternalSemaphore(ExternalSemaphoreTypeFlags fdType,
int fd) override;

Ref<Semaphore> newExternalSemaphore(ExternalSemaphoreTypeFlags handleType,
void* handle, const void* name) override;

void submitSignalSemaphores(Semaphore* const* semaphores,
const uint64_t* values,
int numSemaphores) override;

void submitWaitSemaphores(Semaphore* const* semaphores,
const uint64_t* values,
const uint32_t* timeoutsMs,
int numSemaphores) override;

// Ops
Ref<Conv> newConv(const ConvDesc& desc) override;
Ref<Pool> newPool(const PoolDesc& desc) override;
Expand Down Expand Up @@ -135,6 +151,11 @@ OIDN_NAMESPACE_BEGIN

HIPDevice* device;
hipStream_t stream;

// Temporary storage for semaphore handles and params
std::vector<hipExternalSemaphore_t> semaphoreHandles;
std::vector<hipExternalSemaphoreSignalParams> semaphoreSignalParams;
std::vector<hipExternalSemaphoreWaitParams> semaphoreWaitParams;
};

OIDN_NAMESPACE_END
58 changes: 58 additions & 0 deletions devices/hip/hip_external_semaphore.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright 2026 Intel Corporation
// SPDX-License-Identifier: Apache-2.0

#include "hip_external_semaphore.h"

OIDN_NAMESPACE_BEGIN

HIPExternalSemaphore::HIPExternalSemaphore(Engine* engine,
ExternalSemaphoreTypeFlags fdType,
int fd)
: Semaphore(engine->getDevice()),
type(fdType)
{
// Not yet supported on Linux by HIP.
throw Exception(Error::InvalidArgument, "external semaphore type not supported by the device");
}

HIPExternalSemaphore::HIPExternalSemaphore(Engine* engine,
ExternalSemaphoreTypeFlags handleType,
void* handle, const void* name)
: Semaphore(engine->getDevice()),
type(handleType)
{
hipExternalSemaphoreHandleDesc handleDesc{};
handleDesc.handle.win32.handle = handle;
handleDesc.handle.win32.name = name;

if (handleType == ExternalSemaphoreTypeFlag::OpaqueWin32)
handleDesc.type = hipExternalSemaphoreHandleTypeOpaqueWin32;
else if (handleType == ExternalSemaphoreTypeFlag::OpaqueWin32KMT)
handleDesc.type = hipExternalSemaphoreHandleTypeOpaqueWin32Kmt;
else if (handleType == ExternalSemaphoreTypeFlag::D3D11Fence)
handleDesc.type = hipExternalSemaphoreHandleTypeD3D11Fence;
else if (handleType == ExternalSemaphoreTypeFlag::D3D12Fence)
handleDesc.type = hipExternalSemaphoreHandleTypeD3D12Fence;
else if (handleType == ExternalSemaphoreTypeFlag::KeyedMutex)
handleDesc.type = hipExternalSemaphoreHandleTypeKeyedMutex;
else if (handleType == ExternalSemaphoreTypeFlag::KeyedMutexKMT)
handleDesc.type = hipExternalSemaphoreHandleTypeKeyedMutexKmt;
else if (handleType == ExternalSemaphoreTypeFlag::TimelineSemaphoreWin32)
handleDesc.type = hipExternalSemaphoreHandleTypeTimelineSemaphoreWin32;
else
throw Exception(Error::InvalidArgument, "external semaphore type not supported by the device");

init(handleDesc);
}

void HIPExternalSemaphore::init(const hipExternalSemaphoreHandleDesc& handleDesc)
{
checkError(hipImportExternalSemaphore(&extSem, &handleDesc));
}

HIPExternalSemaphore::~HIPExternalSemaphore()
{
hipDestroyExternalSemaphore(extSem);
}

OIDN_NAMESPACE_END
34 changes: 34 additions & 0 deletions devices/hip/hip_external_semaphore.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright 2026 Intel Corporation
// SPDX-License-Identifier: Apache-2.0

#pragma once

#include "core/semaphore.h"
#include "hip_engine.h"

OIDN_NAMESPACE_BEGIN

class HIPExternalSemaphore : public Semaphore
{
public:
HIPExternalSemaphore(Engine* engine,
ExternalSemaphoreTypeFlags fdType,
int fd);

HIPExternalSemaphore(Engine* engine,
ExternalSemaphoreTypeFlags handleType,
void* handle, const void* name);

~HIPExternalSemaphore();

ExternalSemaphoreTypeFlags getType() const { return type; }
hipExternalSemaphore_t getHandle() const { return extSem; }

private:
ExternalSemaphoreTypeFlags type;
hipExternalSemaphore_t extSem;

void init(const hipExternalSemaphoreHandleDesc& handleDesc);
};

OIDN_NAMESPACE_END