SWDEV-567119 - Windows GL Interop Support (#1892)
Этот коммит содержится в:
@@ -76,7 +76,6 @@ target_sources(rocclr PRIVATE
|
||||
${ROCCLR_SRC_DIR}/device/rocm/rocblitcl.cpp
|
||||
${ROCCLR_SRC_DIR}/device/rocm/roccounters.cpp
|
||||
${ROCCLR_SRC_DIR}/device/rocm/rocdevice.cpp
|
||||
${ROCCLR_SRC_DIR}/device/rocm/rocglinterop.cpp
|
||||
${ROCCLR_SRC_DIR}/device/rocm/rockernel.cpp
|
||||
${ROCCLR_SRC_DIR}/device/rocm/rocmemory.cpp
|
||||
${ROCCLR_SRC_DIR}/device/rocm/rocprintf.cpp
|
||||
@@ -86,4 +85,12 @@ target_sources(rocclr PRIVATE
|
||||
${ROCCLR_SRC_DIR}/device/rocm/rocvirtual.cpp
|
||||
${ROCCLR_SRC_DIR}/device/rocm/rocurilocator.cpp)
|
||||
|
||||
if(UNIX)
|
||||
target_sources(rocclr PRIVATE
|
||||
${ROCCLR_SRC_DIR}/device/rocm/rocglinterop.cpp)
|
||||
else()
|
||||
target_sources(rocclr PRIVATE
|
||||
${ROCCLR_SRC_DIR}/device/rocm/rocglinterop_windows.cpp)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(rocclr PUBLIC WITH_HSA_DEVICE)
|
||||
|
||||
@@ -992,6 +992,15 @@ bool Device::populateOCLDeviceConstants() {
|
||||
info_.uuid_[i] = unique_id[i + 4];
|
||||
}
|
||||
}
|
||||
|
||||
hsa_luid_t localUID = {0};
|
||||
if (HSA_STATUS_SUCCESS ==
|
||||
Hsa::agent_get_info(bkendDevice_, static_cast<hsa_agent_info_t>(HSA_AMD_AGENT_INFO_LUID),
|
||||
&localUID)) {
|
||||
info_.luidLowPart_ = localUID.low;
|
||||
info_.luidHighPart_ = localUID.high;
|
||||
}
|
||||
|
||||
if (HSA_STATUS_SUCCESS !=
|
||||
Hsa::agent_get_info(bkendDevice_,
|
||||
(amd::IS_HIP)
|
||||
@@ -1743,53 +1752,33 @@ bool Device::amdFileWrite(amd::Os::FileDesc handle, void* devicePtr, uint64_t si
|
||||
return true;
|
||||
}
|
||||
|
||||
// ================================================================================================
|
||||
bool Device::bindExternalDevice(uint flags, void* const gfxDevice[], void* gfxContext,
|
||||
bool validateOnly) {
|
||||
#if defined(_WIN32)
|
||||
return false;
|
||||
#else
|
||||
if ((flags & amd::Context::GLDeviceKhr) == 0) return false;
|
||||
|
||||
MesaInterop::MESA_INTEROP_KIND kind = MesaInterop::MESA_INTEROP_NONE;
|
||||
MesaInterop::DisplayHandle display;
|
||||
MesaInterop::ContextHandle context;
|
||||
|
||||
if ((flags & amd::Context::EGLDeviceKhr) != 0) {
|
||||
kind = MesaInterop::MESA_INTEROP_EGL;
|
||||
display.eglDisplay = reinterpret_cast<EGLDisplay>(gfxDevice[amd::Context::GLDeviceKhrIdx]);
|
||||
context.eglContext = reinterpret_cast<EGLContext>(gfxContext);
|
||||
} else {
|
||||
kind = MesaInterop::MESA_INTEROP_GLX;
|
||||
display.glxDisplay = reinterpret_cast<Display*>(gfxDevice[amd::Context::GLDeviceKhrIdx]);
|
||||
context.glxContext = reinterpret_cast<GLXContext>(gfxContext);
|
||||
}
|
||||
|
||||
mesa_glinterop_device_info info;
|
||||
info.version = MESA_GLINTEROP_DEVICE_INFO_VERSION;
|
||||
if (!MesaInterop::Init(kind)) {
|
||||
void* glDevice = gfxDevice[amd::Context::DeviceFlagIdx::GLDeviceKhrIdx];
|
||||
if (!GlInterop::glAssociate(this, flags, gfxContext, glDevice)) {
|
||||
LogError("Failed GlInterop::glAssociate()");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!MesaInterop::GetInfo(info, kind, display, context)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return info_.deviceTopology_.pcie.bus == info.pci_bus &&
|
||||
info_.deviceTopology_.pcie.device == info.pci_device &&
|
||||
info_.deviceTopology_.pcie.function == info.pci_function &&
|
||||
info_.vendorId_ == info.vendor_id && pciDeviceId_ == info.device_id;
|
||||
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
// ================================================================================================
|
||||
bool Device::unbindExternalDevice(uint flags, void* const gfxDevice[], void* gfxContext,
|
||||
bool validateOnly) {
|
||||
#if defined(_WIN32)
|
||||
return false;
|
||||
#else
|
||||
if ((flags & amd::Context::GLDeviceKhr) == 0) return false;
|
||||
|
||||
void* glDevice = gfxDevice[amd::Context::DeviceFlagIdx::GLDeviceKhrIdx];
|
||||
if (glDevice != nullptr) {
|
||||
if (!GlInterop::glDissociate(this, gfxContext, glDevice)) {
|
||||
LogWarning("Failed GlInterop::glDissociate()");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
amd::Memory* Device::findMapTarget(size_t size) const {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2016 - 2021 Advanced Micro Devices, Inc.
|
||||
/* Copyright (c) 2016 - 2025 Advanced Micro Devices, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -18,20 +18,20 @@
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE. */
|
||||
|
||||
#if defined(_WIN32)
|
||||
#error "This file is not expected to be compiled on Windows."
|
||||
#endif
|
||||
|
||||
#include "os/os.hpp"
|
||||
#include "utils/debug.hpp"
|
||||
#include "utils/flags.hpp"
|
||||
#include "device/rocm/rocglinterop.hpp"
|
||||
|
||||
#if !defined(_WIN32)
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
namespace amd::roc {
|
||||
namespace GlInterop {
|
||||
|
||||
namespace MesaInterop {
|
||||
|
||||
#if !defined(_WIN32)
|
||||
static PFNMESAGLINTEROPGLXQUERYDEVICEINFOPROC* GlxInfo = nullptr;
|
||||
static PFNMESAGLINTEROPGLXEXPORTOBJECTPROC* GlxExport = nullptr;
|
||||
static PFNMESAGLINTEROPEGLQUERYDEVICEINFOPROC* EglInfo = nullptr;
|
||||
@@ -39,9 +39,7 @@ static PFNMESAGLINTEROPEGLEXPORTOBJECTPROC* EglExport = nullptr;
|
||||
static MESA_INTEROP_KIND loadedGLAPITypes(MESA_INTEROP_NONE);
|
||||
|
||||
using PFNGLXGETPROCADDRESSPROC = void* (*)(const GLubyte* procname);
|
||||
|
||||
using PFNEGLGETPROCADDRESSPROC = void* (*)(const char* procName);
|
||||
#endif
|
||||
|
||||
static constexpr const char* errorStrings[] = {"MESA_GLINTEROP_SUCCESS",
|
||||
"MESA_GLINTEROP_OUT_OF_RESOURCES",
|
||||
@@ -55,63 +53,55 @@ static constexpr const char* errorStrings[] = {"MESA_GLINTEROP_SUCCESS",
|
||||
"MESA_GLINTEROP_INVALID_MIP_LEVEL",
|
||||
"MESA_GLINTEROP_UNSUPPORTED"};
|
||||
|
||||
bool Supported() {
|
||||
#ifdef _WIN32
|
||||
return false;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !defined(_WIN32)
|
||||
// ================================================================================================
|
||||
// Fallback for older OS' and Mesa versions
|
||||
static void LegacyInitGLX() {
|
||||
if (!GlxInfo) {
|
||||
GlxInfo = (PFNMESAGLINTEROPGLXQUERYDEVICEINFOPROC*)dlsym(RTLD_DEFAULT,
|
||||
"MesaGLInteropGLXQueryDeviceInfo");
|
||||
GlxInfo = reinterpret_cast<PFNMESAGLINTEROPGLXQUERYDEVICEINFOPROC*>(
|
||||
dlsym(RTLD_DEFAULT, "MesaGLInteropGLXQueryDeviceInfo"));
|
||||
}
|
||||
|
||||
if (!GlxExport) {
|
||||
GlxExport =
|
||||
(PFNMESAGLINTEROPGLXEXPORTOBJECTPROC*)dlsym(RTLD_DEFAULT, "MesaGLInteropGLXExportObject");
|
||||
GlxExport = reinterpret_cast<PFNMESAGLINTEROPGLXEXPORTOBJECTPROC*>(
|
||||
dlsym(RTLD_DEFAULT, "MesaGLInteropGLXExportObject"));
|
||||
}
|
||||
}
|
||||
|
||||
// ================================================================================================
|
||||
static void LegacyInitEGL() {
|
||||
if (!EglInfo) {
|
||||
EglInfo = (PFNMESAGLINTEROPEGLQUERYDEVICEINFOPROC*)dlsym(RTLD_DEFAULT,
|
||||
"MesaGLInteropEGLQueryDeviceInfo");
|
||||
EglInfo = reinterpret_cast<PFNMESAGLINTEROPEGLQUERYDEVICEINFOPROC*>(
|
||||
dlsym(RTLD_DEFAULT, "MesaGLInteropEGLQueryDeviceInfo"));
|
||||
}
|
||||
|
||||
if (!EglExport) {
|
||||
EglExport =
|
||||
(PFNMESAGLINTEROPEGLEXPORTOBJECTPROC*)dlsym(RTLD_DEFAULT, "MesaGLInteropEGLExportObject");
|
||||
EglExport = reinterpret_cast<PFNMESAGLINTEROPEGLEXPORTOBJECTPROC*>(
|
||||
dlsym(RTLD_DEFAULT, "MesaGLInteropEGLExportObject"));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// ================================================================================================
|
||||
// Returns true if the required subsystem is supported on the GL device.
|
||||
// Must be called at least once, may be called multiple times.
|
||||
bool Init(MESA_INTEROP_KIND Kind) {
|
||||
#if defined(_WIN32)
|
||||
return false;
|
||||
#else
|
||||
if (loadedGLAPITypes == MESA_INTEROP_NONE) {
|
||||
auto glx_procaddr_fn = (PFNGLXGETPROCADDRESSPROC)dlsym(RTLD_DEFAULT, "glXGetProcAddress");
|
||||
auto egl_procaddr_fn = (PFNEGLGETPROCADDRESSPROC)dlsym(RTLD_DEFAULT, "eglGetProcAddress");
|
||||
static std::once_flag gGlFuncInit;
|
||||
std::call_once(gGlFuncInit, [&]() {
|
||||
auto glx_procaddr_fn =
|
||||
reinterpret_cast<PFNGLXGETPROCADDRESSPROC>(dlsym(RTLD_DEFAULT, "glXGetProcAddress"));
|
||||
auto egl_procaddr_fn =
|
||||
reinterpret_cast<PFNEGLGETPROCADDRESSPROC>(dlsym(RTLD_DEFAULT, "eglGetProcAddress"));
|
||||
|
||||
if (glx_procaddr_fn) {
|
||||
GlxInfo = (PFNMESAGLINTEROPGLXQUERYDEVICEINFOPROC*)glx_procaddr_fn(
|
||||
(const GLubyte*)"glXGLInteropQueryDeviceInfoMESA");
|
||||
GlxExport = (PFNMESAGLINTEROPGLXEXPORTOBJECTPROC*)glx_procaddr_fn(
|
||||
(const GLubyte*)"glXGLInteropExportObjectMESA");
|
||||
GlxInfo = reinterpret_cast<PFNMESAGLINTEROPGLXQUERYDEVICEINFOPROC*>(
|
||||
glx_procaddr_fn(reinterpret_cast<const GLubyte*>("glXGLInteropQueryDeviceInfoMESA")));
|
||||
GlxExport = reinterpret_cast<PFNMESAGLINTEROPGLXEXPORTOBJECTPROC*>(
|
||||
glx_procaddr_fn(reinterpret_cast<const GLubyte*>("glXGLInteropExportObjectMESA")));
|
||||
}
|
||||
|
||||
if (egl_procaddr_fn) {
|
||||
EglInfo = (PFNMESAGLINTEROPEGLQUERYDEVICEINFOPROC*)egl_procaddr_fn(
|
||||
"eglGLInteropQueryDeviceInfoMESA");
|
||||
EglExport =
|
||||
(PFNMESAGLINTEROPEGLEXPORTOBJECTPROC*)egl_procaddr_fn("eglGLInteropExportObjectMESA");
|
||||
EglInfo = reinterpret_cast<PFNMESAGLINTEROPEGLQUERYDEVICEINFOPROC*>(
|
||||
egl_procaddr_fn("eglGLInteropQueryDeviceInfoMESA"));
|
||||
EglExport = reinterpret_cast<PFNMESAGLINTEROPEGLEXPORTOBJECTPROC*>(
|
||||
egl_procaddr_fn("eglGLInteropExportObjectMESA"));
|
||||
}
|
||||
|
||||
if (!GlxInfo || !GlxExport) {
|
||||
@@ -132,17 +122,14 @@ bool Init(MESA_INTEROP_KIND Kind) {
|
||||
}
|
||||
|
||||
loadedGLAPITypes = MESA_INTEROP_KIND(ret);
|
||||
}
|
||||
});
|
||||
|
||||
return ((loadedGLAPITypes & Kind) == Kind);
|
||||
#endif
|
||||
}
|
||||
|
||||
// ================================================================================================
|
||||
bool GetInfo(mesa_glinterop_device_info& info, MESA_INTEROP_KIND Kind, const DisplayHandle display,
|
||||
const ContextHandle context) {
|
||||
#ifdef _WIN32
|
||||
return false;
|
||||
#else
|
||||
assert((loadedGLAPITypes & Kind) == Kind && "Requested interop API is not currently loaded.");
|
||||
int ret;
|
||||
switch (Kind) {
|
||||
@@ -157,19 +144,16 @@ bool GetInfo(mesa_glinterop_device_info& info, MESA_INTEROP_KIND Kind, const Dis
|
||||
return false;
|
||||
}
|
||||
if (ret == MESA_GLINTEROP_SUCCESS) return true;
|
||||
if (ret < int(sizeof(errorStrings) / sizeof(errorStrings[0])))
|
||||
if (ret < static_cast<int>(sizeof(errorStrings) / sizeof(errorStrings[0])))
|
||||
LogPrintfError("Mesa interop: GetInfo failed with \"%s\".\n", errorStrings[ret]);
|
||||
else
|
||||
LogError("Mesa interop: GetInfo failed with invalid error code.\n");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// ================================================================================================
|
||||
bool Export(mesa_glinterop_export_in& in, mesa_glinterop_export_out& out, MESA_INTEROP_KIND Kind,
|
||||
const DisplayHandle display, const ContextHandle context) {
|
||||
#ifdef _WIN32
|
||||
return false;
|
||||
#else
|
||||
assert((loadedGLAPITypes & Kind) == Kind && "Requested interop API is not currently loaded.");
|
||||
int ret;
|
||||
switch (Kind) {
|
||||
@@ -184,12 +168,49 @@ bool Export(mesa_glinterop_export_in& in, mesa_glinterop_export_out& out, MESA_I
|
||||
return false;
|
||||
}
|
||||
if (ret == MESA_GLINTEROP_SUCCESS) return true;
|
||||
if (ret < int(sizeof(errorStrings) / sizeof(errorStrings[0])))
|
||||
if (ret < static_cast<int>(sizeof(errorStrings) / sizeof(errorStrings[0])))
|
||||
LogPrintfError("Mesa interop: Export failed with \"%s\".\n", errorStrings[ret]);
|
||||
else
|
||||
LogError("Mesa interop: Export failed with invalid error code.\n");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
} // namespace MesaInterop
|
||||
|
||||
// ================================================================================================
|
||||
bool glAssociate(Device* device, uint flags, void* gfxContext, void* glDevice) {
|
||||
if ((flags & amd::Context::GLDeviceKhr) == 0) return false;
|
||||
|
||||
MESA_INTEROP_KIND kind;
|
||||
DisplayHandle display;
|
||||
ContextHandle context;
|
||||
|
||||
if ((flags & amd::Context::EGLDeviceKhr) != 0) {
|
||||
kind = MESA_INTEROP_EGL;
|
||||
display.eglDisplay = reinterpret_cast<EGLDisplay>(glDevice);
|
||||
context.eglContext = reinterpret_cast<EGLContext>(gfxContext);
|
||||
} else {
|
||||
kind = MESA_INTEROP_GLX;
|
||||
display.glxDisplay = reinterpret_cast<Display*>(glDevice);
|
||||
context.glxContext = reinterpret_cast<GLXContext>(gfxContext);
|
||||
}
|
||||
|
||||
mesa_glinterop_device_info info = {.version = MESA_GLINTEROP_DEVICE_INFO_VERSION};
|
||||
|
||||
if (!Init(kind) || !GetInfo(info, kind, display, context))
|
||||
return false;
|
||||
|
||||
const auto& pcie = device->info().deviceTopology_.pcie;
|
||||
const auto& dev_info = device->info();
|
||||
return pcie.bus == info.pci_bus &&
|
||||
pcie.device == info.pci_device &&
|
||||
pcie.function == info.pci_function &&
|
||||
dev_info.vendorId_ == info.vendor_id &&
|
||||
dev_info.pcieDeviceId_ == info.device_id;
|
||||
}
|
||||
|
||||
// ================================================================================================
|
||||
bool glDissociate(Device*, void*, void*) {
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace GlInterop
|
||||
} // namespace amd::roc
|
||||
|
||||
@@ -102,7 +102,9 @@ class image_metadata {
|
||||
}
|
||||
};
|
||||
|
||||
namespace MesaInterop {
|
||||
namespace GlInterop {
|
||||
|
||||
#if !defined(_WIN32)
|
||||
enum MESA_INTEROP_KIND { MESA_INTEROP_NONE = 0, MESA_INTEROP_GLX = 1, MESA_INTEROP_EGL = 2 };
|
||||
|
||||
union DisplayHandle {
|
||||
@@ -121,9 +123,6 @@ union ContextHandle {
|
||||
ContextHandle(EGLContext context) : eglContext(context) {}
|
||||
};
|
||||
|
||||
// True if the build supports Mesa interop.
|
||||
bool Supported();
|
||||
|
||||
// Returns true if the required subsystem is supported on the GL device.
|
||||
// Must be called at least once, may be called multiple times.
|
||||
bool Init(MESA_INTEROP_KIND Kind);
|
||||
@@ -133,6 +132,9 @@ bool GetInfo(mesa_glinterop_device_info& info, MESA_INTEROP_KIND Kind, const Dis
|
||||
|
||||
bool Export(mesa_glinterop_export_in& in, mesa_glinterop_export_out& out, MESA_INTEROP_KIND Kind,
|
||||
const DisplayHandle display, const ContextHandle context);
|
||||
} // namespace MesaInterop
|
||||
} // namespace amd::roc
|
||||
#endif
|
||||
|
||||
bool glAssociate(Device* device, uint flags, void* GLplatformContext, void* GLdeviceContext);
|
||||
bool glDissociate(Device* device, void* GLplatformContext, void* GLdeviceContext);
|
||||
} // namespace GlInterop
|
||||
} // namespace amd::roc
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
/* Copyright (c) 2025 Advanced Micro Devices, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE. */
|
||||
|
||||
#include "os/os.hpp"
|
||||
#include "utils/debug.hpp"
|
||||
#include "utils/flags.hpp"
|
||||
#include "device/rocm/rocglinterop.hpp"
|
||||
#include "GL/gl_interop.h"
|
||||
|
||||
namespace amd::roc {
|
||||
namespace GlInterop {
|
||||
|
||||
typedef PROC(WINAPI* PFNWGLGETPROCADDRESS)(LPCSTR name);
|
||||
typedef HGLRC(WINAPI* PFNWGLGETCURRENTCONTEXT)(void);
|
||||
typedef HGLRC(WINAPI* PFNWGLCREATECONTEXT)(HDC hdc);
|
||||
typedef BOOL(WINAPI* PFNWGLDELETECONTEXT)(HGLRC hglrc);
|
||||
typedef BOOL(WINAPI* PFNWGLMAKECURRENT)(HDC hdc, HGLRC hglrc);
|
||||
static PFNWGLGETPROCADDRESS pfnWglGetProcAddress = nullptr;
|
||||
static PFNWGLGETCURRENTCONTEXT pfnWglGetCurrentContext = nullptr;
|
||||
static PFNWGLCREATECONTEXT pfnWglCreateContext = nullptr;
|
||||
static PFNWGLDELETECONTEXT pfnWglDeleteContext = nullptr;
|
||||
static PFNWGLMAKECURRENT pfnWglMakeCurrent = nullptr;
|
||||
static PFNWGLBEGINCLINTEROPAMD wglBeginCLInteropAMD = nullptr;
|
||||
static PFNWGLENDCLINTEROPAMD wglEndCLInteropAMD = nullptr;
|
||||
static PFNWGLRESOURCEATTACHAMD wglResourceAttachAMD = nullptr;
|
||||
static PFNWGLRESOURCEDETACHAMD wglResourceAcquireAMD = nullptr;
|
||||
static PFNWGLRESOURCEDETACHAMD wglResourceReleaseAMD = nullptr;
|
||||
static PFNWGLRESOURCEDETACHAMD wglResourceDetachAMD = nullptr;
|
||||
static PFNWGLGETCONTEXTGPUINFOAMD wglGetContextGPUInfoAMD = nullptr;
|
||||
|
||||
// ================================================================================================
|
||||
bool initGLInteropPrivateExt(void* GLdeviceContext) {
|
||||
static std::once_flag gGlFuncInit;
|
||||
static bool gGlFuncLoaded = false;
|
||||
|
||||
|
||||
std::call_once(gGlFuncInit, [GLdeviceContext]() {
|
||||
if (!GLdeviceContext) {
|
||||
LogError("GLdeviceContext is null");
|
||||
return;
|
||||
}
|
||||
|
||||
HMODULE h = static_cast<HMODULE>(amd::Os::loadLibrary("opengl32.dll"));
|
||||
|
||||
if (!h) {
|
||||
LogError("Couldn't load opengl32.dll");
|
||||
return;
|
||||
}
|
||||
|
||||
pfnWglGetProcAddress =
|
||||
reinterpret_cast<PFNWGLGETPROCADDRESS>(GetProcAddress(h, "wglGetProcAddress"));
|
||||
pfnWglGetCurrentContext =
|
||||
reinterpret_cast<PFNWGLGETCURRENTCONTEXT>(GetProcAddress(h, "wglGetCurrentContext"));
|
||||
pfnWglCreateContext =
|
||||
reinterpret_cast<PFNWGLCREATECONTEXT>(GetProcAddress(h, "wglCreateContext"));
|
||||
pfnWglDeleteContext =
|
||||
reinterpret_cast<PFNWGLDELETECONTEXT>(GetProcAddress(h, "wglDeleteContext"));
|
||||
pfnWglMakeCurrent = reinterpret_cast<PFNWGLMAKECURRENT>(GetProcAddress(h, "wglMakeCurrent"));
|
||||
|
||||
if (!pfnWglGetProcAddress || !pfnWglGetCurrentContext || !pfnWglCreateContext ||
|
||||
!pfnWglDeleteContext || !pfnWglMakeCurrent) {
|
||||
LogError("Couldn't obtain WGL context API");
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a temporary GL context if none is current; WGL extension
|
||||
// functions require some current GL context when loaded.
|
||||
HGLRC fakeRC = nullptr;
|
||||
if (!pfnWglGetCurrentContext()) {
|
||||
fakeRC = pfnWglCreateContext(static_cast<HDC>(GLdeviceContext));
|
||||
if (fakeRC == nullptr) {
|
||||
LogError("Couldn't create temporary WGL context");
|
||||
return;
|
||||
}
|
||||
pfnWglMakeCurrent(static_cast<HDC>(GLdeviceContext), fakeRC);
|
||||
}
|
||||
|
||||
wglBeginCLInteropAMD =
|
||||
reinterpret_cast<PFNWGLBEGINCLINTEROPAMD>(pfnWglGetProcAddress("wglBeginCLInteroperabilityAMD"));
|
||||
wglEndCLInteropAMD = reinterpret_cast<PFNWGLENDCLINTEROPAMD>(pfnWglGetProcAddress("wglEndCLInteroperabilityAMD"));
|
||||
wglResourceAttachAMD = reinterpret_cast<PFNWGLRESOURCEATTACHAMD>(pfnWglGetProcAddress("wglResourceAttachAMD"));
|
||||
wglResourceAcquireAMD = reinterpret_cast<PFNWGLRESOURCEDETACHAMD>(pfnWglGetProcAddress("wglResourceAcquireAMD"));
|
||||
wglResourceReleaseAMD = reinterpret_cast<PFNWGLRESOURCEDETACHAMD>(pfnWglGetProcAddress("wglResourceReleaseAMD"));
|
||||
wglResourceDetachAMD = reinterpret_cast<PFNWGLRESOURCEDETACHAMD>(pfnWglGetProcAddress("wglResourceDetachAMD"));
|
||||
wglGetContextGPUInfoAMD =
|
||||
reinterpret_cast<PFNWGLGETCONTEXTGPUINFOAMD>(pfnWglGetProcAddress("wglGetContextGPUInfoAMD"));
|
||||
|
||||
if (fakeRC) {
|
||||
pfnWglMakeCurrent(nullptr, nullptr);
|
||||
pfnWglDeleteContext(fakeRC);
|
||||
}
|
||||
|
||||
gGlFuncLoaded = wglBeginCLInteropAMD && wglEndCLInteropAMD && wglResourceAttachAMD &&
|
||||
wglResourceAcquireAMD && wglResourceReleaseAMD &&
|
||||
wglResourceDetachAMD && wglGetContextGPUInfoAMD;
|
||||
});
|
||||
|
||||
return gGlFuncLoaded;
|
||||
}
|
||||
|
||||
// ================================================================================================
|
||||
bool glCanInterop(Device* device, void* GLplatformContext, void* GLdeviceContext) {
|
||||
bool canInteroperate = false;
|
||||
|
||||
LUID glAdapterLuid = {0, 0};
|
||||
UINT glChainBitMask = 0;
|
||||
HGLRC hRC = static_cast<HGLRC>(GLplatformContext);
|
||||
|
||||
// get GL context's LUID and chainBitMask from UGL
|
||||
if (wglGetContextGPUInfoAMD(hRC, &glAdapterLuid, &glChainBitMask)) {
|
||||
// match the adapter
|
||||
canInteroperate = device->info().luidLowPart_ == glAdapterLuid.LowPart &&
|
||||
device->info().luidHighPart_ == glAdapterLuid.HighPart &&
|
||||
(((1 << device->index()) & glChainBitMask) != 0);
|
||||
}
|
||||
|
||||
return canInteroperate;
|
||||
}
|
||||
|
||||
// ================================================================================================
|
||||
bool glAssociate(Device* device, uint flags, void* GLplatformContext, void* GLdeviceContext) {
|
||||
static_cast<void>(flags); // unused
|
||||
|
||||
if (!initGLInteropPrivateExt(GLdeviceContext)) return false;
|
||||
|
||||
if (!glCanInterop(device, GLplatformContext, GLdeviceContext)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return wglBeginCLInteropAMD(static_cast<HGLRC>(GLplatformContext), 0) != FALSE;
|
||||
}
|
||||
|
||||
// ================================================================================================
|
||||
bool glDissociate(Device* device, void* GLplatformContext, void* GLdeviceContext) {
|
||||
static_cast<void>(device); // unused
|
||||
|
||||
if (!initGLInteropPrivateExt(GLdeviceContext)) return false;
|
||||
|
||||
return wglEndCLInteropAMD(static_cast<HGLRC>(GLplatformContext), 0) != FALSE;
|
||||
}
|
||||
|
||||
} // namespace GlInterop
|
||||
} // namespace amd::roc
|
||||
@@ -269,11 +269,11 @@ bool Memory::createInteropBuffer(GLenum targetType, int miplevel) {
|
||||
|
||||
const auto& glenv = owner()->getContext().glenv();
|
||||
if (glenv->isEGL()) {
|
||||
if (!MesaInterop::Export(in, out, MesaInterop::MESA_INTEROP_EGL, glenv->getEglDpy(),
|
||||
if (!GlInterop::Export(in, out, GlInterop::MESA_INTEROP_EGL, glenv->getEglDpy(),
|
||||
glenv->getEglOrigCtx()))
|
||||
return false;
|
||||
} else {
|
||||
if (!MesaInterop::Export(in, out, MesaInterop::MESA_INTEROP_GLX, glenv->getDpy(),
|
||||
if (!GlInterop::Export(in, out, GlInterop::MESA_INTEROP_GLX, glenv->getDpy(),
|
||||
glenv->getOrigCtx()))
|
||||
return false;
|
||||
}
|
||||
@@ -1606,4 +1606,3 @@ amd::Image* Image::FindView(cl_image_format format) const {
|
||||
}
|
||||
|
||||
} // namespace amd::roc
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2010 - 2021 Advanced Micro Devices, Inc.
|
||||
/* Copyright (c) 2010 - 2025 Advanced Micro Devices, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -127,10 +127,7 @@ bool Settings::create(bool fullProfile, const amd::Isa& isa, bool enableXNACK, b
|
||||
enableExtension(ClAmdMediaOps);
|
||||
enableExtension(ClAmdMediaOps2);
|
||||
enableExtension(ClKhrImage2dFromBuffer);
|
||||
|
||||
if (MesaInterop::Supported()) {
|
||||
enableExtension(ClKhrGlSharing);
|
||||
}
|
||||
enableExtension(ClKhrGlSharing);
|
||||
|
||||
// Enable platform extension
|
||||
enableExtension(ClAmdDeviceAttributeQuery);
|
||||
|
||||
@@ -349,6 +349,9 @@ typedef struct _HsaNodeProperties
|
||||
HSAuint32 KFDGpuID; // GPU Hash ID generated by KFD
|
||||
|
||||
HSAuint32 FamilyID; // GPU family id
|
||||
|
||||
HSAuint32 LuidLowPart; // Windows Locally Unique Identifier Low 4 bytes
|
||||
HSAuint32 LuidHighPart; // Windows Locally Unique Identifier High 4 bytes
|
||||
} HsaNodeProperties;
|
||||
|
||||
|
||||
|
||||
@@ -1713,6 +1713,10 @@ hsa_status_t GpuAgent::GetInfo(hsa_agent_info_t attribute, void* value) const {
|
||||
case HSA_AMD_AGENT_INFO_PM4_EMULATION:
|
||||
*((bool*)value) = properties_.Capability2.ui32.AqlEmulationPm4_;
|
||||
break;
|
||||
case HSA_AMD_AGENT_INFO_LUID:
|
||||
static_cast<hsa_luid_t*>(value)->low = properties_.LuidLowPart;
|
||||
static_cast<hsa_luid_t*>(value)->high = properties_.LuidHighPart;
|
||||
break;
|
||||
default:
|
||||
return HSA_STATUS_ERROR_INVALID_ARGUMENT;
|
||||
break;
|
||||
|
||||
@@ -5691,6 +5691,14 @@ typedef void* hsa_handle_t;
|
||||
typedef int hsa_handle_t;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Platform-independent container for a Windows LUID.
|
||||
*/
|
||||
typedef struct hsa_luid_s {
|
||||
uint32_t low; //!< Luid low 4 bytes, valid only on Windows
|
||||
uint32_t high; //!< Luid high 4 bytes, valid only on Windows
|
||||
} hsa_luid_t;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*
|
||||
|
||||
@@ -709,7 +709,12 @@ typedef enum hsa_amd_agent_info_s {
|
||||
/**
|
||||
* The agent uses PM4 emulation mode.
|
||||
*/
|
||||
HSA_AMD_AGENT_INFO_PM4_EMULATION = 0xA119
|
||||
HSA_AMD_AGENT_INFO_PM4_EMULATION = 0xA119,
|
||||
/**
|
||||
* Queries for the LUID that identifies a hardware node. The LUID is only
|
||||
* valid on Windows. The type of this attribute is LUID.
|
||||
*/
|
||||
HSA_AMD_AGENT_INFO_LUID = 0xA11A,
|
||||
} hsa_amd_agent_info_t;
|
||||
|
||||
/**
|
||||
|
||||
Ссылка в новой задаче
Block a user