From d4758bc29ebc2654b79089d533b4ea2a0f46936c Mon Sep 17 00:00:00 2001 From: Jin Jung Date: Mon, 12 Jan 2026 11:10:46 -0800 Subject: [PATCH] SWDEV-570501 - Add Windows support for hipGraphicsGLRegisterBuffer (#2323) --- projects/clr/hipamd/src/hip_stream.cpp | 3 +-- .../clr/rocclr/device/rocm/rocglinterop.hpp | 2 ++ .../device/rocm/rocglinterop_windows.cpp | 25 +++++++++++++++++++ projects/clr/rocclr/device/rocm/rocmemory.cpp | 17 ++++++++----- projects/clr/rocclr/device/rocm/rocmemory.hpp | 5 +++- projects/clr/rocclr/device/rocm/rocrctx.hpp | 10 ++++---- .../libhsakmt/include/hsakmt/hsakmttypes.h | 1 + .../core/common/hsa_table_interface.cpp | 17 +++++-------- .../runtime/hsa-runtime/core/inc/runtime.h | 8 +++--- .../hsa-runtime/core/runtime/hsa_ext_amd.cpp | 16 +++++------- .../hsa-runtime/core/runtime/runtime.cpp | 24 +++++++++--------- .../runtime/hsa-runtime/inc/hsa.h | 8 ++++++ .../runtime/hsa-runtime/inc/hsa_ext_amd.h | 15 +++++------ 13 files changed, 90 insertions(+), 61 deletions(-) diff --git a/projects/clr/hipamd/src/hip_stream.cpp b/projects/clr/hipamd/src/hip_stream.cpp index bb087adff0..b9b84033b6 100644 --- a/projects/clr/hipamd/src/hip_stream.cpp +++ b/projects/clr/hipamd/src/hip_stream.cpp @@ -74,10 +74,9 @@ bool Stream::Create() { return create(); } // ================================================================================================ void Stream::Destroy(hip::Stream* stream, bool forceDestroy) { stream->device().removeFromActiveQueues(stream); - stream->device_->RemoveStream(stream); + stream->GetDevice()->RemoveStream(stream); stream->SetForceDestroy(forceDestroy); stream->release(); - stream = nullptr; } // ================================================================================================ diff --git a/projects/clr/rocclr/device/rocm/rocglinterop.hpp b/projects/clr/rocclr/device/rocm/rocglinterop.hpp index ee10fe139d..56cae23c86 100644 --- a/projects/clr/rocclr/device/rocm/rocglinterop.hpp +++ b/projects/clr/rocclr/device/rocm/rocglinterop.hpp @@ -136,5 +136,7 @@ bool Export(mesa_glinterop_export_in& in, mesa_glinterop_export_out& out, MESA_I bool glAssociate(Device* device, uint flags, void* GLplatformContext, void* GLdeviceContext); bool glDissociate(Device* device, void* GLplatformContext, void* GLdeviceContext); +bool Export(amd::Memory* mem, GLenum targetType, int miplevel, hsa_handle_t* handle, int* offset); + } // namespace GlInterop } // namespace amd::roc diff --git a/projects/clr/rocclr/device/rocm/rocglinterop_windows.cpp b/projects/clr/rocclr/device/rocm/rocglinterop_windows.cpp index 1bb66f124c..415e882424 100644 --- a/projects/clr/rocclr/device/rocm/rocglinterop_windows.cpp +++ b/projects/clr/rocclr/device/rocm/rocglinterop_windows.cpp @@ -23,6 +23,7 @@ #include "utils/flags.hpp" #include "device/rocm/rocglinterop.hpp" #include "GL/gl_interop.h" +#include "platform/interop_gl.hpp" namespace amd::roc { namespace GlInterop { @@ -156,5 +157,29 @@ bool glDissociate(Device* device, void* GLplatformContext, void* GLdeviceContext return wglEndCLInteropAMD(static_cast(GLplatformContext), 0) != FALSE; } +// ================================================================================================ +bool Export(amd::Memory* mem, GLenum targetType, int miplevel, hsa_handle_t* handle, int* offset) { + 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(obj->getGLName()); + + assert(targetType == GL_ARRAY_BUFFER && "Only GL_ARRAY_BUFFER is supported"); + constexpr GLenum type = GL_RESOURCE_ATTACH_VERTEXBUFFER_AMD; + + const auto glRenderContext = reinterpret_cast(GLContext); + GLResource glResource = {.type = type, .name = name}; + GLResourceData glResourceData = {.version = GL_RESOURCE_DATA_VERSION}; + + if (!wglResourceAttachAMD(glRenderContext, static_cast(&glResource), &glResourceData)) + return false; + *handle = reinterpret_cast(glResourceData.handle); + *offset = static_cast(glResourceData.offset); + + return true; +} + } // namespace GlInterop } // namespace amd::roc diff --git a/projects/clr/rocclr/device/rocm/rocmemory.cpp b/projects/clr/rocclr/device/rocm/rocmemory.cpp index 7e7c3f31d9..5624f8569d 100644 --- a/projects/clr/rocclr/device/rocm/rocmemory.cpp +++ b/projects/clr/rocclr/device/rocm/rocmemory.cpp @@ -202,13 +202,13 @@ void Memory::cpuUnmap(device::VirtualDevice& vDev) { } // ================================================================================================ -hsa_status_t Memory::interopMapBuffer(amd::Os::FileDesc fdn) { +hsa_status_t Memory::interopMapBuffer(hsa_handle_t fdn, hsa_interop_map_flag_t flags) { hsa_agent_t agent = dev().getBackendDevice(); size_t size; size_t metadata_size = 0; void* metadata; auto fd = fdn; - hsa_status_t status = Hsa::interop_map_buffer(1, &agent, fd, 0, &size, &interop_deviceMemory_, + hsa_status_t status = Hsa::interop_map_buffer(1, &agent, fd, flags, &size, &interop_deviceMemory_, &metadata_size, (const void**)&metadata); ClPrint(amd::LOG_DEBUG, amd::LOG_MEM, "Map Interop memory %p, size 0x%zx", interop_deviceMemory_, size); @@ -231,7 +231,14 @@ hsa_status_t Memory::interopMapBuffer(amd::Os::FileDesc fdn) { // ================================================================================================ bool Memory::createInteropBuffer(GLenum targetType, int miplevel) { #if IS_WINDOWS - return false; + hsa_handle_t handle; + int offset; + + if (!GlInterop::Export(owner(), targetType, miplevel, &handle, &offset)) return false; + if (interopMapBuffer(handle, HSA_INTEROP_MAP_FLAG_KMT_HANDLE) != HSA_STATUS_SUCCESS) return false; + + deviceMemory_ = static_cast(interop_deviceMemory_) + offset; + return true; #else assert(owner()->isInterop() && "Object is not an interop object."); @@ -895,9 +902,7 @@ bool Buffer::create(bool alloc_local) { auto ext_memory = interop->asExternalMemory(); amd::GLObject* glObject = interop->asGLObject(); if (ext_memory != nullptr) { - hsa_status_t status = interopMapBuffer(ext_memory->Handle()); - if (status != HSA_STATUS_SUCCESS) return false; - return true; + return interopMapBuffer(ext_memory->Handle()) == HSA_STATUS_SUCCESS; } else if (glObject != nullptr) { return createInteropBuffer(GL_ARRAY_BUFFER, 0); } diff --git a/projects/clr/rocclr/device/rocm/rocmemory.hpp b/projects/clr/rocclr/device/rocm/rocmemory.hpp index 120ca18705..d6d2876000 100644 --- a/projects/clr/rocclr/device/rocm/rocmemory.hpp +++ b/projects/clr/rocclr/device/rocm/rocmemory.hpp @@ -126,7 +126,10 @@ class Memory : public device::Memory { // Free / deregister device memory. virtual void destroy() = 0; - hsa_status_t interopMapBuffer(amd::Os::FileDesc fdn); + + // Map interop buffer + hsa_status_t interopMapBuffer(hsa_handle_t fdn, + hsa_interop_map_flag_t flags = HSA_INTEROP_MAP_FLAG_NONE); // Place interop object into HSA's flat address space bool createInteropBuffer(GLenum targetType, int miplevel); diff --git a/projects/clr/rocclr/device/rocm/rocrctx.hpp b/projects/clr/rocclr/device/rocm/rocrctx.hpp index fb811aa67c..e612e4eaa1 100644 --- a/projects/clr/rocclr/device/rocm/rocrctx.hpp +++ b/projects/clr/rocclr/device/rocm/rocrctx.hpp @@ -386,11 +386,11 @@ class Hsa : public amd::AllStatic { return ROCR_DYN(hsa_amd_memory_unlock)(host_ptr); } static hsa_status_t interop_map_buffer(uint32_t num_agents, hsa_agent_t* agents, - amd::Os::FileDesc interop_handle, - uint32_t flags, size_t* size, - void** ptr, size_t* metadata_size, const void** metadata) { - return ROCR_DYN(hsa_amd_interop_map_buffer)(num_agents, agents, interop_handle, flags, size, - ptr, metadata_size, metadata); + hsa_handle_t interop_handle, uint32_t flags, + size_t* size, void** ptr, size_t* metadata_size, + const void** metadata) { + return ROCR_DYN(hsa_amd_interop_map_buffer)(num_agents, agents, interop_handle, flags, size, ptr, + metadata_size, metadata); } static hsa_status_t interop_unmap_buffer(void* ptr) { return ROCR_DYN(hsa_amd_interop_unmap_buffer)(ptr); diff --git a/projects/rocr-runtime/libhsakmt/include/hsakmt/hsakmttypes.h b/projects/rocr-runtime/libhsakmt/include/hsakmt/hsakmttypes.h index 4e45a1d4b4..0faff5ad69 100644 --- a/projects/rocr-runtime/libhsakmt/include/hsakmt/hsakmttypes.h +++ b/projects/rocr-runtime/libhsakmt/include/hsakmt/hsakmttypes.h @@ -1516,6 +1516,7 @@ typedef union struct { unsigned int requiresVAddr : 1; // Requires virtual address + unsigned int kmtHandle : 1; // Handle is a KMT handle } ui32; } HSA_REGISTER_MEM_FLAGS; diff --git a/projects/rocr-runtime/runtime/hsa-runtime/core/common/hsa_table_interface.cpp b/projects/rocr-runtime/runtime/hsa-runtime/core/common/hsa_table_interface.cpp index 0c06d8c774..b8580ca955 100644 --- a/projects/rocr-runtime/runtime/hsa-runtime/core/common/hsa_table_interface.cpp +++ b/projects/rocr-runtime/runtime/hsa-runtime/core/common/hsa_table_interface.cpp @@ -1092,17 +1092,12 @@ hsa_status_t HSA_API } // Mirrors Amd Extension Apis -hsa_status_t HSA_API hsa_amd_interop_map_buffer(uint32_t num_agents, - hsa_agent_t* agents, - hsa_handle_t interop_handle, - uint32_t flags, - size_t* size, - void** ptr, - size_t* metadata_size, - const void** metadata) { - return amdExtTable->hsa_amd_interop_map_buffer_fn( - num_agents, agents, interop_handle, - flags, size, ptr, metadata_size, metadata); +hsa_status_t HSA_API hsa_amd_interop_map_buffer(uint32_t num_agents, hsa_agent_t* agents, + hsa_handle_t interop_handle, uint32_t flags, + size_t* size, void** ptr, size_t* metadata_size, + const void** metadata) { + return amdExtTable->hsa_amd_interop_map_buffer_fn(num_agents, agents, interop_handle, flags, size, + ptr, metadata_size, metadata); } // Mirrors Amd Extension Apis diff --git a/projects/rocr-runtime/runtime/hsa-runtime/core/inc/runtime.h b/projects/rocr-runtime/runtime/hsa-runtime/core/inc/runtime.h index 4aa92ae95d..2f357abb64 100644 --- a/projects/rocr-runtime/runtime/hsa-runtime/core/inc/runtime.h +++ b/projects/rocr-runtime/runtime/hsa-runtime/core/inc/runtime.h @@ -347,11 +347,9 @@ class Runtime { hsa_signal_value_t value, hsa_amd_signal_handler handler, void* arg); - hsa_status_t InteropMap(uint32_t num_agents, Agent** agents, - hsa_handle_t interop_handle, - uint32_t flags, size_t* size, - void** ptr, size_t* metadata_size, - const void** metadata); + hsa_status_t InteropMap(uint32_t num_agents, Agent** agents, hsa_handle_t handle, + hsa_interop_map_flag_t flags, size_t* size, void** ptr, + size_t* metadata_size, const void** metadata); hsa_status_t InteropUnmap(void* ptr); diff --git a/projects/rocr-runtime/runtime/hsa-runtime/core/runtime/hsa_ext_amd.cpp b/projects/rocr-runtime/runtime/hsa-runtime/core/runtime/hsa_ext_amd.cpp index b81c919eeb..91af1f46aa 100644 --- a/projects/rocr-runtime/runtime/hsa-runtime/core/runtime/hsa_ext_amd.cpp +++ b/projects/rocr-runtime/runtime/hsa-runtime/core/runtime/hsa_ext_amd.cpp @@ -992,19 +992,15 @@ hsa_status_t hsa_amd_agent_memory_pool_get_info( CATCH; } -hsa_status_t hsa_amd_interop_map_buffer(uint32_t num_agents, - hsa_agent_t* agents, - hsa_handle_t interop_handle, - uint32_t flags, size_t* size, - void** ptr, size_t* metadata_size, - const void** metadata) { - static const int tinyArraySize=8; +hsa_status_t hsa_amd_interop_map_buffer(uint32_t num_agents, hsa_agent_t* agents, + hsa_handle_t interop_handle, uint32_t flags, size_t* size, + void** ptr, size_t* metadata_size, const void** metadata) { + static const int tinyArraySize = 8; TRY; IS_OPEN(); IS_BAD_PTR(agents); IS_BAD_PTR(size); IS_BAD_PTR(ptr); - if (flags != 0) return HSA_STATUS_ERROR_INVALID_ARGUMENT; if (num_agents == 0) return HSA_STATUS_ERROR_INVALID_ARGUMENT; core::Agent* short_agents[tinyArraySize]; @@ -1025,8 +1021,8 @@ hsa_status_t hsa_amd_interop_map_buffer(uint32_t num_agents, } auto ret = core::Runtime::runtime_singleton_->InteropMap( - num_agents, core_agents, interop_handle, flags, size, ptr, metadata_size, - metadata); + num_agents, core_agents, interop_handle, static_cast(flags), size, + ptr, metadata_size, metadata); return ret; CATCH; diff --git a/projects/rocr-runtime/runtime/hsa-runtime/core/runtime/runtime.cpp b/projects/rocr-runtime/runtime/hsa-runtime/core/runtime/runtime.cpp index 254e7b80d8..965a0d5c63 100644 --- a/projects/rocr-runtime/runtime/hsa-runtime/core/runtime/runtime.cpp +++ b/projects/rocr-runtime/runtime/hsa-runtime/core/runtime/runtime.cpp @@ -868,24 +868,21 @@ hsa_status_t Runtime::SetAsyncSignalHandler(hsa_signal_t signal, return HSA_STATUS_SUCCESS; } -hsa_status_t Runtime::InteropMap(uint32_t num_agents, Agent** agents, - hsa_handle_t interop_handle, - uint32_t flags, - size_t* size, void** ptr, +hsa_status_t Runtime::InteropMap(uint32_t num_agents, Agent** agents, hsa_handle_t handle, + hsa_interop_map_flag_t flags, size_t* size, void** ptr, size_t* metadata_size, const void** metadata) { - static const int tinyArraySize=8; + constexpr int tinyArraySize = 8; HsaGraphicsResourceInfo info; HSAuint32 short_nodes[tinyArraySize]; HSAuint32* nodes = short_nodes; - static_assert(sizeof(HSAint64) >= sizeof(interop_handle), - "HSAint64 too small for interop_handle"); + static_assert(sizeof(HSAint64) >= sizeof(handle), "HSAint64 too small for interop_handle"); HSAint64 resource_handle = #ifdef _WIN32 - static_cast(reinterpret_cast(interop_handle)); + static_cast(reinterpret_cast(handle)); #else - static_cast(interop_handle); + static_cast(handle); #endif if (num_agents > tinyArraySize) { @@ -903,9 +900,12 @@ hsa_status_t Runtime::InteropMap(uint32_t num_agents, Agent** agents, agents[i]->GetInfo(static_cast(HSA_AMD_AGENT_INFO_DRIVER_NODE_ID), &nodes[i]); } - if (HSAKMT_CALL(hsaKmtRegisterGraphicsHandleToNodes(resource_handle, &info, num_agents, - nodes)) != HSAKMT_STATUS_SUCCESS) - return HSA_STATUS_ERROR; + const HSA_REGISTER_MEM_FLAGS reg_flags = { + .ui32 = {.kmtHandle = ((flags & HSA_INTEROP_MAP_FLAG_KMT_HANDLE) != 0)}}; + + auto status = + hsaKmtRegisterGraphicsHandleToNodesExt(resource_handle, &info, num_agents, nodes, reg_flags); + if (status != HSAKMT_STATUS_SUCCESS) return HSA_STATUS_ERROR; assert(num_agents > 0); auto& driver = agents[0]->driver(); diff --git a/projects/rocr-runtime/runtime/hsa-runtime/inc/hsa.h b/projects/rocr-runtime/runtime/hsa-runtime/inc/hsa.h index 80e7e5e9d5..af023a9658 100644 --- a/projects/rocr-runtime/runtime/hsa-runtime/inc/hsa.h +++ b/projects/rocr-runtime/runtime/hsa-runtime/inc/hsa.h @@ -5691,6 +5691,14 @@ typedef void* hsa_handle_t; typedef int hsa_handle_t; #endif +/** + * @brief Interop map flags. + */ +typedef uint32_t hsa_interop_map_flag_t; + +#define HSA_INTEROP_MAP_FLAG_NONE 0u +#define HSA_INTEROP_MAP_FLAG_KMT_HANDLE (1u << 0) + /** * @brief Platform-independent container for a Windows LUID. */ diff --git a/projects/rocr-runtime/runtime/hsa-runtime/inc/hsa_ext_amd.h b/projects/rocr-runtime/runtime/hsa-runtime/inc/hsa_ext_amd.h index 8c0a64afa5..a9104b4cea 100644 --- a/projects/rocr-runtime/runtime/hsa-runtime/inc/hsa_ext_amd.h +++ b/projects/rocr-runtime/runtime/hsa-runtime/inc/hsa_ext_amd.h @@ -2307,7 +2307,8 @@ hsa_status_t HSA_API * * @param[in] agents List of accessing agents. * - * @param[in] interop_handle Handle of interop buffer (dmabuf handle in Linux) + * @param[in] interop_handle interop buffer handle (FD on Linux and HANDLE on + * Windows) * * @param [in] flags Reserved, must be 0 * @@ -2328,14 +2329,10 @@ hsa_status_t HSA_API * * @retval HSA_STATUS_ERROR_INVALID_ARGUMENT all other errors */ -hsa_status_t HSA_API hsa_amd_interop_map_buffer(uint32_t num_agents, - hsa_agent_t* agents, - hsa_handle_t interop_handle, - uint32_t flags, - size_t* size, - void** ptr, - size_t* metadata_size, - const void** metadata); +hsa_status_t HSA_API hsa_amd_interop_map_buffer(uint32_t num_agents, hsa_agent_t* agents, + hsa_handle_t interop_handle, uint32_t flags, + size_t* size, void** ptr, size_t* metadata_size, + const void** metadata); /** * @brief Removes a previously mapped interop object from HSA's flat address space.