@@ -103,9 +103,13 @@ VkResult vkml_allocate_basics(
103103 VkCommandPool* command_pool,
104104 uint32_t * queue_family_index,
105105 bool request_neural_statistics,
106- bool * neural_statistics_device_enabled);
106+ bool * neural_statistics_device_enabled,
107+ bool request_host_memory_import,
108+ VgfHostMemoryImportCapabilities* host_memory_import_capabilities);
107109
108110// Helper functions to dump VGF Delegate Boundary Inputs
111+ constexpr const char * kVgfHostMemoryImportEnableEnv =
112+ " EXECUTORCH_VGF_ENABLE_HOST_MEMORY_IMPORT" ;
109113constexpr const char * kVgfDumpInputsDirEnv = " EXECUTORCH_VGF_DUMP_INPUTS_DIR" ;
110114constexpr const char * kVgfDumpInputsAndExitEnv =
111115 " EXECUTORCH_VGF_DUMP_INPUTS_AND_EXIT" ;
@@ -418,8 +422,11 @@ class VGFBackend final : public ::executorch::runtime::BackendInterface {
418422
419423 VkResult result;
420424 neural_statistics_config_ = get_vgf_neural_statistics_runtime_config ();
425+ const bool request_host_memory_import =
426+ env_flag_enabled (kVgfHostMemoryImportEnableEnv );
421427
422- // Fetch basic vulkan objects once
428+ // Fetch basic Vulkan objects once. Device extensions must be selected here,
429+ // before vkCreateDevice; VgfRepr only receives already-created handles.
423430 result = vkml_allocate_basics (
424431 &vk_instance,
425432 &vk_physical_device,
@@ -428,7 +435,9 @@ class VGFBackend final : public ::executorch::runtime::BackendInterface {
428435 &vk_command_pool,
429436 &vk_queue_family_index,
430437 neural_statistics_config_.requested ,
431- &neural_statistics_device_enabled_);
438+ &neural_statistics_device_enabled_,
439+ request_host_memory_import,
440+ &host_memory_import_capabilities_);
432441 if (result != VK_SUCCESS ) {
433442 ET_LOG (
434443 Error, " Failed to initialize the Vulkan device error 0x%08X" , result);
@@ -535,7 +544,8 @@ class VGFBackend final : public ::executorch::runtime::BackendInterface {
535544 vk_queue_family_index,
536545 neural_statistics_config_.requested ,
537546 neural_statistics_device_enabled_,
538- neural_statistics_config_.mode_index );
547+ neural_statistics_config_.mode_index ,
548+ host_memory_import_capabilities_);
539549
540550#ifdef ET_EVENT_TRACER_ENABLED
541551 event_tracer_end_profiling_delegate (event_tracer, allocate_repr_event);
@@ -865,6 +875,7 @@ class VGFBackend final : public ::executorch::runtime::BackendInterface {
865875 vk_queue_family_index = UINT32_MAX ;
866876 neural_statistics_config_ = {};
867877 neural_statistics_device_enabled_ = false ;
878+ host_memory_import_capabilities_ = {};
868879 is_initialized_ = false ;
869880 // Do not call volkFinalize(): the Vulkan backend shares the loader.
870881 }
@@ -879,6 +890,7 @@ class VGFBackend final : public ::executorch::runtime::BackendInterface {
879890 uint32_t vk_queue_family_index = UINT32_MAX ;
880891 VgfNeuralStatisticsRuntimeConfig neural_statistics_config_{};
881892 bool neural_statistics_device_enabled_ = false ;
893+ VgfHostMemoryImportCapabilities host_memory_import_capabilities_{};
882894 bool is_initialized_ = false ;
883895};
884896
@@ -896,12 +908,17 @@ VkResult vkml_allocate_basics(
896908 VkCommandPool* command_pool,
897909 uint32_t * queue_family_index,
898910 bool request_neural_statistics,
899- bool * neural_statistics_device_enabled) {
911+ bool * neural_statistics_device_enabled,
912+ bool request_host_memory_import,
913+ VgfHostMemoryImportCapabilities* host_memory_import_capabilities) {
900914 VkResult result;
901915
902916 if (neural_statistics_device_enabled != nullptr ) {
903917 *neural_statistics_device_enabled = false ;
904918 }
919+ if (host_memory_import_capabilities != nullptr ) {
920+ *host_memory_import_capabilities = {};
921+ }
905922
906923 if (VK_SUCCESS != volkInitialize ()) {
907924 ET_LOG (Error, " Volk failed to initialize" );
@@ -1156,6 +1173,59 @@ VkResult vkml_allocate_basics(
11561173
11571174 vector<const char *> requested_exts;
11581175
1176+ bool enable_host_memory_import_device = false ;
1177+ #if defined(VK_EXT_external_memory_host)
1178+ const bool host_memory_import_advertised = std::any_of (
1179+ available.begin (), available.end (), [](const auto & ext_avail) {
1180+ return std::strcmp (
1181+ VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME ,
1182+ ext_avail.extensionName ) == 0 ;
1183+ });
1184+
1185+ VkDeviceSize min_imported_host_pointer_alignment = 0 ;
1186+ if (host_memory_import_advertised) {
1187+ VkPhysicalDeviceExternalMemoryHostPropertiesEXT host_memory_properties{
1188+ .sType =
1189+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT ,
1190+ .pNext = nullptr ,
1191+ };
1192+ VkPhysicalDeviceProperties2 properties_2{
1193+ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 ,
1194+ .pNext = &host_memory_properties,
1195+ };
1196+ vkGetPhysicalDeviceProperties2 (*physical_device, &properties_2);
1197+ min_imported_host_pointer_alignment =
1198+ host_memory_properties.minImportedHostPointerAlignment ;
1199+ }
1200+
1201+ if (host_memory_import_capabilities != nullptr ) {
1202+ host_memory_import_capabilities->physical_device_advertised =
1203+ host_memory_import_advertised;
1204+ host_memory_import_capabilities->min_imported_host_pointer_alignment =
1205+ min_imported_host_pointer_alignment;
1206+ }
1207+
1208+ enable_host_memory_import_device = vgf_host_memory_import_should_be_enabled (
1209+ request_host_memory_import, host_memory_import_advertised);
1210+ if (enable_host_memory_import_device) {
1211+ requested_exts.push_back (VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME );
1212+ } else if (request_host_memory_import) {
1213+ ET_LOG (
1214+ Info,
1215+ " %s was requested but the Vulkan physical device does not expose %s" ,
1216+ kVgfHostMemoryImportEnableEnv ,
1217+ VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME );
1218+ }
1219+ #else
1220+ if (request_host_memory_import) {
1221+ ET_LOG (
1222+ Info,
1223+ " %s was requested but Vulkan headers do not expose "
1224+ " VK_EXT_external_memory_host" ,
1225+ kVgfHostMemoryImportEnableEnv );
1226+ }
1227+ #endif
1228+
11591229 const bool bfloat16_extension_available = std::any_of (
11601230 available.begin (), available.end (), [](const auto & ext_avail) {
11611231 return std::strcmp (
@@ -1263,12 +1333,36 @@ VkResult vkml_allocate_basics(
12631333 // Load the device with volk and populate function pointers
12641334 volkLoadDevice (*device);
12651335
1336+ if (host_memory_import_capabilities != nullptr ) {
1337+ // Only a successful vkCreateDevice makes extension enablement
1338+ // authoritative. Physical-device advertisement alone is insufficient for
1339+ // later zero-copy code to use VK_EXT_external_memory_host device
1340+ // functionality.
1341+ host_memory_import_capabilities->logical_device_enabled =
1342+ enable_host_memory_import_device;
1343+ ET_LOG (
1344+ Info,
1345+ " VGF host memory import: requested=%d advertised=%d enabled=%d "
1346+ " minImportedHostPointerAlignment=%llu" ,
1347+ static_cast <int >(request_host_memory_import),
1348+ static_cast <int >(
1349+ host_memory_import_capabilities->physical_device_advertised ),
1350+ static_cast <int >(
1351+ host_memory_import_capabilities->logical_device_enabled ),
1352+ static_cast <unsigned long long >(
1353+ host_memory_import_capabilities
1354+ ->min_imported_host_pointer_alignment ));
1355+ }
1356+
12661357 vkGetDeviceQueue (*device, qf, 0 , queue);
12671358
12681359 VkCommandPoolCreateInfo poolInfo{
12691360 .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO ,
12701361 .pNext = nullptr ,
1271- .flags = 0 ,
1362+ // VGF records a persistent per-repr command buffer. Host-memory import
1363+ // may later rebind descriptors and re-record only that command buffer.
1364+ // Keep the legacy flags=0 behavior unless the extension is truly enabled.
1365+ .flags = vgf_command_pool_flags (enable_host_memory_import_device),
12721366 .queueFamilyIndex = qf,
12731367 };
12741368 result = vkCreateCommandPool (*device, &poolInfo, nullptr , command_pool);
0 commit comments