Files
TheRock/rocm-systems/projects/clr/rocclr/device/rocm/rocglinterop_windows.cpp
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

237 lines
9.1 KiB
C++

/*
* Copyright (c) Advanced Micro Devices, Inc., or its affiliates.
*
* SPDX-License-Identifier: MIT
*/
#include "os/os.hpp"
#include "utils/debug.hpp"
#include "utils/flags.hpp"
#include "device/rocm/rocglinterop.hpp"
#include "GL/gl_interop.h"
#include "platform/interop_gl.hpp"
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,
bool validateOnly) {
static_cast<void>(flags); // unused
if (!initGLInteropPrivateExt(GLdeviceContext)) return false;
if (!glCanInterop(device, GLplatformContext, GLdeviceContext)) {
return false;
}
// validateOnly: compatibility confirmed, skip starting a real interop session.
if (validateOnly) {
return true;
}
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;
}
// ================================================================================================
bool Export(amd::Memory* mem, GLenum targetType, int miplevel, hsa_handle_t* handle,
hsa_handle_t* resHandle, int* offset, void* image_srd, const unsigned image_srd_size) {
assert(mem->getInteropObj() != nullptr);
assert(mem->getInteropObj()->asGLObject() != nullptr);
const auto* obj = mem->getInteropObj()->asGLObject();
const auto GLContext = mem->getContext().info().hCtx_;
const auto name = static_cast<uint>(obj->getGLName());
GLenum type;
switch (obj->getCLGLObjectType()) {
case CL_GL_OBJECT_BUFFER:
type = GL_RESOURCE_ATTACH_VERTEXBUFFER_AMD;
break;
case CL_GL_OBJECT_RENDERBUFFER:
type = GL_RESOURCE_ATTACH_RENDERBUFFER_AMD;
break;
case CL_GL_OBJECT_TEXTURE_BUFFER:
case CL_GL_OBJECT_TEXTURE1D:
case CL_GL_OBJECT_TEXTURE1D_ARRAY:
case CL_GL_OBJECT_TEXTURE2D:
case CL_GL_OBJECT_TEXTURE2D_ARRAY:
case CL_GL_OBJECT_TEXTURE3D:
type = GL_RESOURCE_ATTACH_TEXTURE_AMD;
break;
default:
LogPrintfError("Unknown OpenGL interop type: 0x%x", obj->getCLGLObjectType());
return false;
}
const auto glRenderContext = reinterpret_cast<HGLRC>(GLContext);
GLResource glResource = {.type = type, .name = name};
GLResourceData glResourceData = {.version = GL_RESOURCE_DATA_VERSION};
if (!wglResourceAttachAMD(glRenderContext, static_cast<GLvoid*>(&glResource), &glResourceData))
return false;
*handle = reinterpret_cast<hsa_handle_t>(glResourceData.handle);
*resHandle = reinterpret_cast<hsa_handle_t>(glResourceData.mbResHandle);
*offset = static_cast<int>(glResourceData.offset);
if (image_srd && image_srd_size >= glResourceData.textureSRDSize) {
std::memcpy(image_srd, glResourceData.textureSRD, glResourceData.textureSRDSize);
}
return true;
}
// ================================================================================================
bool Detach(amd::Memory* mem, hsa_handle_t handle) {
assert(mem->getInteropObj() != nullptr);
assert(mem->getInteropObj()->asGLObject() != nullptr);
const auto* obj = mem->getInteropObj()->asGLObject();
const auto GLContext = mem->getContext().info().hCtx_;
GLenum type;
switch (obj->getCLGLObjectType()) {
case CL_GL_OBJECT_BUFFER:
type = GL_RESOURCE_ATTACH_VERTEXBUFFER_AMD;
break;
case CL_GL_OBJECT_RENDERBUFFER:
type = GL_RESOURCE_ATTACH_RENDERBUFFER_AMD;
break;
case CL_GL_OBJECT_TEXTURE_BUFFER:
case CL_GL_OBJECT_TEXTURE1D:
case CL_GL_OBJECT_TEXTURE1D_ARRAY:
case CL_GL_OBJECT_TEXTURE2D:
case CL_GL_OBJECT_TEXTURE2D_ARRAY:
case CL_GL_OBJECT_TEXTURE3D:
type = GL_RESOURCE_ATTACH_TEXTURE_AMD;
break;
default:
LogPrintfError("Unknown OpenGL interop type: 0x%x", obj->getCLGLObjectType());
return false;
}
const auto glRenderContext = reinterpret_cast<HGLRC>(GLContext);
GLResource hRes = {};
hRes.mbResHandle = reinterpret_cast<GLuintp>(handle);
hRes.type = type;
return (wglResourceDetachAMD(glRenderContext, &hRes)) ? true : false;
}
} // namespace GlInterop
} // namespace amd::roc