From 5935cfec7898fc0d78a0c3f0626ae853ffafe64b Mon Sep 17 00:00:00 2001 From: Andrzej Janik Date: Tue, 13 May 2025 02:20:23 +0200 Subject: [PATCH] Work around broken AMD Adrenalin 25.5.1 driver (#366) For reasons unknown AMD Adrenalin 25.5.1 ships with comgr that presents itself as version 2, but expects ABI for veersion 3. Add a workaround --- comgr/src/lib.rs | 29 ++++++++++++++++++++++++++--- ext/amd_comgr-sys/README | 4 ++-- ext/amd_comgr-sys/src/comgr2.rs | 11 +++++++++++ ext/amd_comgr-sys/src/comgr3.rs | 11 +++++++++++ 4 files changed, 50 insertions(+), 5 deletions(-) diff --git a/comgr/src/lib.rs b/comgr/src/lib.rs index 7682645..7588bde 100644 --- a/comgr/src/lib.rs +++ b/comgr/src/lib.rs @@ -245,14 +245,37 @@ impl Comgr { }) .or_else(|_| { unsafe { libloading::Library::new(os::COMGR2) }.and_then(|lib| { - Ok(Comgr::V2(unsafe { - amd_comgr_sys::comgr2::Comgr2::from_library(lib)? - })) + Ok(if Self::is_broken_v2(&lib) { + Comgr::V3(unsafe { amd_comgr_sys::comgr3::Comgr3::from_library(lib)? }) + } else { + Comgr::V2(unsafe { amd_comgr_sys::comgr2::Comgr2::from_library(lib)? }) + }) }) }) .map_err(Into::into) } + // For reasons unknown, on AMD Adrenalin 25.5.1, AMD ships amd_comgr_2.dll that shows up as + // version 2.9.0, but actually uses the 3.X ABI. This is our best effort to detect it. + // Version 25.3.1 returns 2.8.0, which seem to be the last version that actually uses the 2 ABI + fn is_broken_v2(lib: &libloading::Library) -> bool { + if cfg!(not(windows)) { + return false; + } + let amd_comgr_get_version = match unsafe { + lib.get::( + b"amd_comgr_get_version\0", + ) + } { + Ok(symbol) => symbol, + Err(_) => return false, + }; + let mut major = 0; + let mut minor = 0; + unsafe { (amd_comgr_get_version)(&mut major, &mut minor) }; + (major, minor) >= (2, 9) + } + fn do_action( &self, kind: ActionKind, diff --git a/ext/amd_comgr-sys/README b/ext/amd_comgr-sys/README index ac4bf14..a3e8e79 100644 --- a/ext/amd_comgr-sys/README +++ b/ext/amd_comgr-sys/README @@ -1,4 +1,4 @@ # On ROCm 6.3 and lower -bindgen --rust-target 1.77 /opt/rocm-6.3.4/include/amd_comgr/amd_comgr.h -o src/comgr2.rs --no-layout-tests --default-enum-style=newtype --no-derive-debug --must-use-type amd_comgr_status_t --allowlist-var "^AMD_COMGR.*$" --dynamic-loading Comgr2 --allowlist-function amd_comgr_do_action --allowlist-function amd_comgr_action_data_get_data --allowlist-function amd_comgr_action_info_set_isa_name --allowlist-function amd_comgr_action_info_set_language --allowlist-function amd_comgr_create_action_info --allowlist-function amd_comgr_create_data --allowlist-function amd_comgr_create_data_set --allowlist-function amd_comgr_data_set_add --allowlist-function amd_comgr_destroy_action_info --allowlist-function amd_comgr_destroy_data_set --allowlist-function amd_comgr_get_data --allowlist-function amd_comgr_set_data --allowlist-function amd_comgr_set_data_name --allowlist-function amd_comgr_action_info_set_option_list +bindgen --rust-target 1.77 /opt/rocm-6.3.4/include/amd_comgr/amd_comgr.h -o src/comgr2.rs --no-layout-tests --default-enum-style=newtype --no-derive-debug --must-use-type amd_comgr_status_t --allowlist-var "^AMD_COMGR.*$" --dynamic-loading Comgr2 --allowlist-function amd_comgr_do_action --allowlist-function amd_comgr_action_data_get_data --allowlist-function amd_comgr_action_info_set_isa_name --allowlist-function amd_comgr_action_info_set_language --allowlist-function amd_comgr_create_action_info --allowlist-function amd_comgr_create_data --allowlist-function amd_comgr_create_data_set --allowlist-function amd_comgr_data_set_add --allowlist-function amd_comgr_destroy_action_info --allowlist-function amd_comgr_destroy_data_set --allowlist-function amd_comgr_get_data --allowlist-function amd_comgr_set_data --allowlist-function amd_comgr_set_data_name --allowlist-function amd_comgr_action_info_set_option_list --allowlist-function amd_comgr_get_version # On ROCm 6.4 and higher -bindgen --rust-target 1.77 /opt/rocm/include/amd_comgr/amd_comgr.h -o src/comgr3.rs --no-layout-tests --default-enum-style=newtype --no-derive-debug --must-use-type amd_comgr_status_t --allowlist-var "^AMD_COMGR.*$" --dynamic-loading Comgr3 --allowlist-function amd_comgr_do_action --allowlist-function amd_comgr_action_data_get_data --allowlist-function amd_comgr_action_info_set_isa_name --allowlist-function amd_comgr_action_info_set_language --allowlist-function amd_comgr_create_action_info --allowlist-function amd_comgr_create_data --allowlist-function amd_comgr_create_data_set --allowlist-function amd_comgr_data_set_add --allowlist-function amd_comgr_destroy_action_info --allowlist-function amd_comgr_destroy_data_set --allowlist-function amd_comgr_get_data --allowlist-function amd_comgr_set_data --allowlist-function amd_comgr_set_data_name --allowlist-function amd_comgr_action_info_set_option_list +bindgen --rust-target 1.77 /opt/rocm/include/amd_comgr/amd_comgr.h -o src/comgr3.rs --no-layout-tests --default-enum-style=newtype --no-derive-debug --must-use-type amd_comgr_status_t --allowlist-var "^AMD_COMGR.*$" --dynamic-loading Comgr3 --allowlist-function amd_comgr_do_action --allowlist-function amd_comgr_action_data_get_data --allowlist-function amd_comgr_action_info_set_isa_name --allowlist-function amd_comgr_action_info_set_language --allowlist-function amd_comgr_create_action_info --allowlist-function amd_comgr_create_data --allowlist-function amd_comgr_create_data_set --allowlist-function amd_comgr_data_set_add --allowlist-function amd_comgr_destroy_action_info --allowlist-function amd_comgr_destroy_data_set --allowlist-function amd_comgr_get_data --allowlist-function amd_comgr_set_data --allowlist-function amd_comgr_set_data_name --allowlist-function amd_comgr_action_info_set_option_list --allowlist-function amd_comgr_get_version diff --git a/ext/amd_comgr-sys/src/comgr2.rs b/ext/amd_comgr-sys/src/comgr2.rs index 27995ec..9811644 100644 --- a/ext/amd_comgr-sys/src/comgr2.rs +++ b/ext/amd_comgr-sys/src/comgr2.rs @@ -256,6 +256,8 @@ pub struct amd_comgr_action_kind_s(pub ::std::os::raw::c_uint); pub use self::amd_comgr_action_kind_s as amd_comgr_action_kind_t; pub struct Comgr2 { __library: ::libloading::Library, + pub amd_comgr_get_version: + Result, pub amd_comgr_create_data: Result< unsafe extern "C" fn( kind: amd_comgr_data_kind_t, @@ -363,6 +365,7 @@ impl Comgr2 { L: Into<::libloading::Library>, { let __library = library.into(); + let amd_comgr_get_version = __library.get(b"amd_comgr_get_version\0").map(|sym| *sym); let amd_comgr_create_data = __library.get(b"amd_comgr_create_data\0").map(|sym| *sym); let amd_comgr_set_data = __library.get(b"amd_comgr_set_data\0").map(|sym| *sym); let amd_comgr_set_data_name = __library.get(b"amd_comgr_set_data_name\0").map(|sym| *sym); @@ -395,6 +398,7 @@ impl Comgr2 { let amd_comgr_do_action = __library.get(b"amd_comgr_do_action\0").map(|sym| *sym); Ok(Comgr2 { __library, + amd_comgr_get_version, amd_comgr_create_data, amd_comgr_set_data, amd_comgr_set_data_name, @@ -411,6 +415,13 @@ impl Comgr2 { amd_comgr_do_action, }) } + #[doc = " @brief Get the version of the code object manager interface\n supported.\n\n An interface is backwards compatible with an implementation with an\n equal major version, and a greater than or equal minor version.\n\n @param[out] major Major version number.\n\n @param[out] minor Minor version number."] + pub unsafe fn amd_comgr_get_version(&self, major: *mut usize, minor: *mut usize) { + (self + .amd_comgr_get_version + .as_ref() + .expect("Expected function, got error."))(major, minor) + } #[must_use] #[doc = " @brief Create a data object that can hold data of a specified kind.\n\n Data objects are reference counted and are destroyed when the\n reference count reaches 0. When a data object is created its\n reference count is 1, it has 0 bytes of data, it has an empty name,\n and it has no metadata.\n\n @param[in] kind The kind of data the object is intended to hold.\n\n @param[out] data A handle to the data object created. Its reference\n count is set to 1.\n\n @retval ::AMD_COMGR_STATUS_SUCCESS The function has\n been executed successfully.\n\n @retval ::AMD_COMGR_STATUS_ERROR_INVALID_ARGUMENT @p\n kind is an invalid data kind, or @p\n AMD_COMGR_DATA_KIND_UNDEF. @p data is NULL.\n\n @retval ::AMD_COMGR_STATUS_ERROR_OUT_OF_RESOURCES\n Unable to create the data object as out of resources."] pub unsafe fn amd_comgr_create_data( diff --git a/ext/amd_comgr-sys/src/comgr3.rs b/ext/amd_comgr-sys/src/comgr3.rs index 6679576..c0c1474 100644 --- a/ext/amd_comgr-sys/src/comgr3.rs +++ b/ext/amd_comgr-sys/src/comgr3.rs @@ -246,6 +246,8 @@ pub struct amd_comgr_action_kind_s(pub ::std::os::raw::c_uint); pub use self::amd_comgr_action_kind_s as amd_comgr_action_kind_t; pub struct Comgr3 { __library: ::libloading::Library, + pub amd_comgr_get_version: + Result, pub amd_comgr_create_data: Result< unsafe extern "C" fn( kind: amd_comgr_data_kind_t, @@ -353,6 +355,7 @@ impl Comgr3 { L: Into<::libloading::Library>, { let __library = library.into(); + let amd_comgr_get_version = __library.get(b"amd_comgr_get_version\0").map(|sym| *sym); let amd_comgr_create_data = __library.get(b"amd_comgr_create_data\0").map(|sym| *sym); let amd_comgr_set_data = __library.get(b"amd_comgr_set_data\0").map(|sym| *sym); let amd_comgr_set_data_name = __library.get(b"amd_comgr_set_data_name\0").map(|sym| *sym); @@ -385,6 +388,7 @@ impl Comgr3 { let amd_comgr_do_action = __library.get(b"amd_comgr_do_action\0").map(|sym| *sym); Ok(Comgr3 { __library, + amd_comgr_get_version, amd_comgr_create_data, amd_comgr_set_data, amd_comgr_set_data_name, @@ -401,6 +405,13 @@ impl Comgr3 { amd_comgr_do_action, }) } + #[doc = " @brief Get the version of the code object manager interface\n supported.\n\n An interface is backwards compatible with an implementation with an\n equal major version, and a greater than or equal minor version.\n\n @param[out] major Major version number.\n\n @param[out] minor Minor version number."] + pub unsafe fn amd_comgr_get_version(&self, major: *mut usize, minor: *mut usize) { + (self + .amd_comgr_get_version + .as_ref() + .expect("Expected function, got error."))(major, minor) + } #[must_use] #[doc = " @brief Create a data object that can hold data of a specified kind.\n\n Data objects are reference counted and are destroyed when the\n reference count reaches 0. When a data object is created its\n reference count is 1, it has 0 bytes of data, it has an empty name,\n and it has no metadata.\n\n @param[in] kind The kind of data the object is intended to hold.\n\n @param[out] data A handle to the data object created. Its reference\n count is set to 1.\n\n @retval ::AMD_COMGR_STATUS_SUCCESS The function has\n been executed successfully.\n\n @retval ::AMD_COMGR_STATUS_ERROR_INVALID_ARGUMENT @p\n kind is an invalid data kind, or @p\n AMD_COMGR_DATA_KIND_UNDEF. @p data is NULL.\n\n @retval ::AMD_COMGR_STATUS_ERROR_OUT_OF_RESOURCES\n Unable to create the data object as out of resources."] pub unsafe fn amd_comgr_create_data(