compute-runtime/shared/source/os_interface/windows/external_semaphore_windows.cpp

189 lines
6.4 KiB
C++

/*
* Copyright (C) 2025 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#include "shared/source/os_interface/windows/external_semaphore_windows.h"
#include "shared/source/os_interface/os_library.h"
#include "shared/source/os_interface/windows/d3dkmthk_wrapper.h"
#include "shared/source/os_interface/windows/gdi_interface.h"
#include "shared/source/os_interface/windows/wddm/wddm.h"
#include "shared/source/os_interface/windows/windows_wrapper.h"
#include <memory>
typedef VOID(NTAPI *_RtlInitUnicodeString)(PUNICODE_STRING destinationString, PCWSTR sourceString);
typedef VOID(NTAPI *_NtOpenDirectoryObject)(PHANDLE directoryHandle, ACCESS_MASK desiredAccess, POBJECT_ATTRIBUTES objectAttributes);
namespace NEO {
std::unique_ptr<ExternalSemaphore> ExternalSemaphore::create(OSInterface *osInterface, ExternalSemaphore::Type type, void *handle, int fd) {
if (osInterface) {
if (osInterface->getDriverModel()->getDriverModelType() == DriverModelType::wddm) {
auto externalSemaphore = ExternalSemaphoreWindows::create(osInterface);
bool result = externalSemaphore->importSemaphore(handle, fd, 0, nullptr, type, false);
if (result == false) {
return nullptr;
}
return externalSemaphore;
}
}
return nullptr;
}
std::unique_ptr<ExternalSemaphoreWindows> ExternalSemaphoreWindows::create(OSInterface *osInterface) {
auto extSemWindows = std::make_unique<ExternalSemaphoreWindows>();
extSemWindows->osInterface = osInterface;
extSemWindows->state = SemaphoreState::Initial;
return extSemWindows;
}
bool ExternalSemaphoreWindows::importSemaphore(void *extHandle, int fd, uint32_t flags, const char *name, Type type, bool isNative) {
switch (type) {
case ExternalSemaphore::D3d12Fence:
case ExternalSemaphore::OpaqueWin32:
break;
default:
return false;
}
HANDLE syncNtHandle = nullptr;
this->type = type;
auto wddm = this->osInterface->getDriverModel()->as<Wddm>();
syncNtHandle = reinterpret_cast<HANDLE>(extHandle);
if (type == ExternalSemaphore::OpaqueWin32) {
auto moduleHandle = GetModuleHandleA("ntdll.dll");
_RtlInitUnicodeString rtlInitUnicodeString = (_RtlInitUnicodeString)GetProcAddress(moduleHandle, "RtlInitUnicodeString");
_NtOpenDirectoryObject ntOpenDirectoryObject = (_NtOpenDirectoryObject)GetProcAddress(moduleHandle, "NtOpenDirectoryObject");
HANDLE rootDirectory;
OBJECT_ATTRIBUTES objectAttributesRootDirectory;
UNICODE_STRING unicodeNameRootDirectory;
PUNICODE_STRING pUnicodeNameRootDirectory = NULL;
wchar_t baseName[] = L"\\BaseNamedObjects";
rtlInitUnicodeString(&unicodeNameRootDirectory, baseName);
pUnicodeNameRootDirectory = &unicodeNameRootDirectory;
InitializeObjectAttributes(&objectAttributesRootDirectory, pUnicodeNameRootDirectory, 0, nullptr, nullptr);
ntOpenDirectoryObject(&rootDirectory, 0x0004 /* DIRECTORY_CREATE_OBJECT */, &objectAttributesRootDirectory);
this->pCpuAddress = MapViewOfFile(syncNtHandle, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0);
auto sharedMemoryContentHeader = this->getSharedMemoryContentHeader();
auto access = sharedMemoryContentHeader->access;
auto pSyncName = &sharedMemoryContentHeader->sharedSyncName[0];
this->pLastSignaledValue = &sharedMemoryContentHeader->lastSignaledValue;
syncNtHandle = nullptr;
OBJECT_ATTRIBUTES objectAttributes;
UNICODE_STRING unicodeName;
PUNICODE_STRING pUnicodeName = NULL;
const wchar_t *pName = reinterpret_cast<wchar_t *>(pSyncName);
if (pName) {
rtlInitUnicodeString(&unicodeName, pName);
pUnicodeName = &unicodeName;
}
InitializeObjectAttributes(&objectAttributes, pUnicodeName, 0, rootDirectory, nullptr);
D3DKMT_OPENSYNCOBJECTNTHANDLEFROMNAME openName = {};
openName.dwDesiredAccess = access;
openName.pObjAttrib = &objectAttributes;
auto status = wddm->getGdi()->openSyncObjectNtHandleFromName(&openName);
if (status != STATUS_SUCCESS) {
return false;
}
syncNtHandle = openName.hNtHandle;
}
D3DKMT_OPENSYNCOBJECTFROMNTHANDLE2 open = {};
open.hNtHandle = syncNtHandle;
open.hDevice = wddm->getDeviceHandle();
open.Flags.NoGPUAccess = (type == ExternalSemaphore::D3d12Fence);
auto status = wddm->getGdi()->openSyncObjectFromNtHandle2(&open);
if (status != STATUS_SUCCESS) {
return false;
}
this->syncHandle = open.hSyncObject;
return true;
}
bool ExternalSemaphoreWindows::enqueueWait(uint64_t *fenceValue) {
auto wddm = this->osInterface->getDriverModel()->as<Wddm>();
D3DDDI_WAITFORSYNCHRONIZATIONOBJECTFROMCPU_FLAGS waitFlags = {};
waitFlags.WaitAny = false;
D3DKMT_WAITFORSYNCHRONIZATIONOBJECTFROMCPU wait = {};
wait.hDevice = wddm->getDeviceHandle();
wait.ObjectCount = 1;
wait.ObjectHandleArray = &this->syncHandle;
uint64_t lastSignaledValue = 0;
if (this->type == ExternalSemaphore::OpaqueWin32) {
lastSignaledValue = *this->pLastSignaledValue;
wait.FenceValueArray = &lastSignaledValue;
} else {
wait.FenceValueArray = fenceValue;
}
wait.FenceValueArray = fenceValue;
wait.hAsyncEvent = nullptr;
wait.Flags = waitFlags;
auto status = wddm->getGdi()->waitForSynchronizationObjectFromCpu(&wait);
if (status != STATUS_SUCCESS) {
return false;
}
this->state = SemaphoreState::Signaled;
return true;
}
bool ExternalSemaphoreWindows::enqueueSignal(uint64_t *fenceValue) {
auto wddm = this->osInterface->getDriverModel()->as<Wddm>();
D3DKMT_SIGNALSYNCHRONIZATIONOBJECTFROMCPU signal = {};
signal.hDevice = wddm->getDeviceHandle();
signal.ObjectCount = 1;
signal.ObjectHandleArray = &this->syncHandle;
uint64_t lastSignaledValue = 0;
if (this->type == ExternalSemaphore::OpaqueWin32) {
lastSignaledValue = *this->pLastSignaledValue + 2;
signal.FenceValueArray = &lastSignaledValue;
} else {
signal.FenceValueArray = fenceValue;
}
auto status = wddm->getGdi()->signalSynchronizationObjectFromCpu(&signal);
if (status != STATUS_SUCCESS) {
return false;
}
if (this->type == ExternalSemaphore::OpaqueWin32) {
*this->pLastSignaledValue += 2;
}
this->state = SemaphoreState::Signaled;
return true;
}
} // namespace NEO