@@ -589,12 +589,141 @@ DeviceInterface* SetProviderSessionOptions(OrtSessionOptions& session_options,
589589 p_device = GetDeviceInterface (DeviceType::NvTensorRtRtx);
590590 }
591591
592+ #if USE_WINML
593+ // Get model device config
594+ std::optional<uint32_t > config_device_id = config.model .hardware_device_id ;
595+ std::optional<uint32_t > config_vendor_id = config.model .hardware_vendor_id ;
596+ std::optional<std::string> config_device_type = config.model .hardware_device_type ;
597+ // for OpenVINO, use "device_type" in provider_options exclusively if it's provided
598+ std::optional<std::string> config_ov_device_type = std::nullopt ;
599+ if (provider_options.name == " OpenVINO" ) {
600+ for (auto & option : provider_options.options ) {
601+ if (option.first == " device_type" ) {
602+ config_ov_device_type = option.second ;
603+ }
604+ }
605+ if (config_ov_device_type.has_value ()) {
606+ config_device_id = std::nullopt ;
607+ config_vendor_id = std::nullopt ;
608+ config_device_type = std::nullopt ;
609+ } else if (!(config_device_id.has_value () || config_vendor_id.has_value () || config_device_type.has_value ())) {
610+ config_ov_device_type = " CPU" ;
611+ }
612+ }
613+ std::optional<OrtHardwareDeviceType> config_device_type_enum;
614+ if (config_device_type.has_value ()) {
615+ if (*config_device_type == " CPU" ) {
616+ config_device_type_enum = OrtHardwareDeviceType_CPU;
617+ } else if (*config_device_type == " GPU" ) {
618+ config_device_type_enum = OrtHardwareDeviceType_GPU;
619+ } else if (*config_device_type == " NPU" ) {
620+ config_device_type_enum = OrtHardwareDeviceType_NPU;
621+ } else {
622+ throw std::runtime_error (" Unsupported hardware device type: " + *config_device_type);
623+ }
624+ }
625+
626+ // Match EP device with EP name in provider options and model device config
627+ // include\onnxruntime\core\graph\constants.h
628+ const static std::unordered_map<std::string, std::string> s_providerNameToExecutionProvider{
629+ {" QNN" , " QNNExecutionProvider" },
630+ {" WebGPU" , " WebGpuExecutionProvider" },
631+ {" OpenVINO" , " OpenVINOExecutionProvider" },
632+ {" VitisAI" , " VitisAIExecutionProvider" },
633+ {" NvTensorRtRtx" , " NvTensorRTRTXExecutionProvider" },
634+ };
635+ std::string epName{};
636+ if (auto search = s_providerNameToExecutionProvider.find (provider_options.name ); search != s_providerNameToExecutionProvider.end ()) {
637+ epName = search->second ;
638+ }
639+
640+ size_t num_devices;
641+ const OrtEpDevice* const * device_ptrs;
642+ Ort::api->GetEpDevices (&GetOrtEnv (), &device_ptrs, &num_devices);
643+ std::vector<const OrtEpDevice*> ep_devices_ptrs;
644+ ep_devices_ptrs.reserve (num_devices);
645+ for (size_t i = 0 ; i < num_devices; ++i) {
646+ const OrtHardwareDevice* hardware_device = Ort::api->EpDevice_Device (device_ptrs[i]);
647+ const uint32_t hardware_device_id = Ort::api->HardwareDevice_DeviceId (hardware_device);
648+ const uint32_t hardware_vendor_id = Ort::api->HardwareDevice_VendorId (hardware_device);
649+ const OrtHardwareDeviceType hardware_device_type = Ort::api->HardwareDevice_Type (hardware_device);
650+
651+ auto check_ov_device_type = [&config_ov_device_type, &provider_options](const OrtEpDevice* device_ptr) -> bool {
652+ if (provider_options.name != " OpenVINO" ) {
653+ return true ;
654+ } else if (!config_ov_device_type.has_value ()) {
655+ return true ;
656+ } else {
657+ const OrtKeyValuePairs* keyvals = Ort::api->EpDevice_EpMetadata (device_ptr);
658+ size_t num_entries;
659+ const char * const * keys = nullptr ;
660+ const char * const * values = nullptr ;
661+ Ort::api->GetKeyValuePairs (keyvals, &keys, &values, &num_entries);
662+ for (int kvi = 0 ; kvi < num_entries; kvi++) {
663+ const std::string key = keys[kvi];
664+ const std::string val = values[kvi];
665+ if (key == " ov_device" && val == config_ov_device_type) {
666+ return true ;
667+ }
668+ }
669+ return false ;
670+ }
671+ };
672+ bool hardware_device_id_matched = (!config_device_id.has_value ()) || config_device_id.value () == hardware_device_id;
673+ bool hardware_vendor_id_matched = (!config_vendor_id.has_value ()) || config_vendor_id.value () == hardware_vendor_id;
674+ bool hardware_device_type_matched = (!config_device_type_enum.has_value ()) ||
675+ config_device_type_enum.value () == hardware_device_type;
676+ bool hardware_ov_device_type_matched = check_ov_device_type (device_ptrs[i]);
677+
678+ // Append matched EP device
679+ if (Ort::api->EpDevice_EpName (device_ptrs[i]) == epName &&
680+ hardware_device_id_matched &&
681+ hardware_vendor_id_matched &&
682+ hardware_device_type_matched &&
683+ hardware_ov_device_type_matched) {
684+ ep_devices_ptrs.push_back (device_ptrs[i]);
685+ // WinML Hotfix: DML and WebGPU EP factories currently only support one device at a time
686+ // OpenVINO also supports only one device at a time
687+ if (provider_options.name == " DML" || provider_options.name == " WebGPU" || provider_options.name == " OpenVINO" ) {
688+ break ;
689+ }
690+ }
691+ }
692+
693+ // No need to append if we can't find a device.
694+ if (!ep_devices_ptrs.empty ()) {
695+ std::vector<const char *> keys, values;
696+ for (auto & option : provider_options.options ) {
697+ // WinML Hotfix: remove backend_type and backend_path from QNN provider options
698+ static const std::set<std::string> qnn_options_to_remove{" backend_type" , " backend_path" };
699+ if (provider_options.name == " QNN" &&
700+ qnn_options_to_remove.find (option.first ) != qnn_options_to_remove.end ()) {
701+ continue ;
702+ }
703+
704+ // 'device_type' is not a supported option for OpenVINO when SessionOptionsAppendExecutionProvider_V2 is used.
705+ if (provider_options.name == " OpenVINO" && option.first == " device_type" ) {
706+ continue ;
707+ }
708+ keys.emplace_back (option.first .c_str ());
709+ values.emplace_back (option.second .c_str ());
710+ }
711+
712+ Ort::api->SessionOptionsAppendExecutionProvider_V2 (
713+ &session_options,
714+ &GetOrtEnv (),
715+ ep_devices_ptrs.data (), ep_devices_ptrs.size (),
716+ keys.data (), values.data (), keys.size ());
717+ }
718+ #else
592719 std::vector<const char *> keys, values;
593720 for (auto & option : provider_options.options ) {
594721 keys.emplace_back (option.first .c_str ());
595722 values.emplace_back (option.second .c_str ());
596723 }
597724 session_options.AppendExecutionProvider (provider_options.name .c_str (), keys.data (), values.data (), keys.size ());
725+
726+ #endif
598727 }
599728 }
600729 return p_device;
0 commit comments