55#include < cctype>
66#include < map>
77#include < set>
8+ #include < sstream>
89
910#include < utility>
1011#include " core/providers/shared_library/provider_api.h"
1920
2021namespace onnxruntime {
2122namespace openvino_ep {
23+
2224void ParseConfigOptions (ProviderInfo& pi) {
2325 if (pi.config_options == nullptr )
2426 return ;
@@ -378,7 +380,7 @@ struct OpenVINOProviderFactory : IExecutionProviderFactory {
378380 // The implementation of the SessionOptionsAppendExecutionProvider C API function automatically adds EP options to
379381 // the session option configurations with the key prefix "ep.<lowercase_ep_name>.".
380382 // Extract those EP options into a new "provider_options" map.
381- std::string lowercase_ep_name = kOpenVINOExecutionProvider ;
383+ std::string lowercase_ep_name = " OpenVINOExecutionProvider " ;
382384 std::transform (lowercase_ep_name.begin (), lowercase_ep_name.end (), lowercase_ep_name.begin (), [](unsigned char c) {
383385 return static_cast <char >(std::tolower (c));
384386 });
@@ -433,6 +435,25 @@ struct OpenVINO_Provider : Provider {
433435 return std::make_shared<OpenVINOProviderFactory>(pi, SharedContext::Get ());
434436 }
435437
438+ Status CreateIExecutionProvider (const OrtHardwareDevice* const * /* devices*/ ,
439+ const OrtKeyValuePairs* const * /* ep_metadata*/ ,
440+ size_t num_devices,
441+ ProviderOptions& provider_options,
442+ const OrtSessionOptions& session_options,
443+ const OrtLogger& logger,
444+ std::unique_ptr<IExecutionProvider>& ep) override {
445+ if (num_devices != 1 ) {
446+ return Status (common::ONNXRUNTIME, ORT_EP_FAIL, " OpenVINO EP only supports one device." );
447+ }
448+ std::array<const void *, 2 > params{
449+ &provider_options,
450+ &session_options.GetConfigOptions (),
451+ };
452+ auto ep_factory = CreateExecutionProviderFactory (¶ms);
453+ ep = ep_factory->CreateProvider (session_options, logger);
454+ return Status::OK ();
455+ }
456+
436457 void Initialize () override {
437458 }
438459
@@ -443,6 +464,106 @@ struct OpenVINO_Provider : Provider {
443464 ProviderInfo_OpenVINO_Impl info_;
444465}; // OpenVINO_Provider
445466
467+ // OrtEpApi infrastructure to be able to use the OpenVINO EP as an OrtEpFactory for auto EP selection.
468+ struct OpenVINOEpFactory : OrtEpFactory {
469+ OpenVINOEpFactory (const OrtApi& ort_api_in)
470+ : ort_api{ort_api_in} {
471+ GetName = GetNameImpl;
472+ GetVendor = GetVendorImpl;
473+ GetSupportedDevices = GetSupportedDevicesImpl;
474+ CreateEp = CreateEpImpl;
475+ ReleaseEp = ReleaseEpImpl;
476+ }
477+
478+ static const char * GetNameImpl (const OrtEpFactory*) noexcept {
479+ return ep_name;
480+ }
481+
482+ static const char * GetVendorImpl (const OrtEpFactory*) noexcept {
483+ return vendor;
484+ }
485+
486+ static OrtStatus* GetSupportedDevicesImpl (OrtEpFactory* ep_factory,
487+ const OrtHardwareDevice* const * devices,
488+ size_t num_devices,
489+ OrtEpDevice** ep_devices,
490+ size_t max_ep_devices,
491+ size_t * num_ep_devices) noexcept {
492+ if (!ep_factory || !devices || !ep_devices || !num_ep_devices) {
493+ return nullptr ;
494+ }
495+
496+ *num_ep_devices = 0 ;
497+ const OpenVINOEpFactory* factory = static_cast <const OpenVINOEpFactory*>(ep_factory);
498+
499+ // Simple device discovery and EP device creation
500+ for (size_t i = 0 ; i < num_devices && *num_ep_devices < max_ep_devices; ++i) {
501+ const std::uint32_t vendorId = factory->ort_api .HardwareDevice_VendorId (devices[i]);
502+ const char * vendorName = factory->ort_api .HardwareDevice_Vendor (devices[i]);
503+
504+ // Check if this is an Intel device
505+ if ((vendorId == intel_vendor_id) ||
506+ (vendorName && std::string (vendorName).find (" Intel" ) != std::string::npos)) {
507+
508+ const auto device_type = factory->ort_api .HardwareDevice_Type (devices[i]);
509+
510+ // Map device type to OpenVINO string
511+ const char * device_type_str = nullptr ;
512+ switch (device_type) {
513+ case OrtHardwareDeviceType_CPU: device_type_str = " CPU" ; break ;
514+ case OrtHardwareDeviceType_GPU: device_type_str = " GPU" ; break ;
515+ case OrtHardwareDeviceType_NPU: device_type_str = " NPU" ; break ;
516+ default : continue ; // Skip unknown device types
517+ }
518+
519+ // Create EP options
520+ OrtKeyValuePairs* ep_options = nullptr ;
521+ factory->ort_api .CreateKeyValuePairs (&ep_options);
522+ factory->ort_api .AddKeyValuePair (ep_options, " device_type" , device_type_str);
523+
524+ // Create EP device
525+ OrtEpDevice* ep_device = nullptr ;
526+ OrtStatus* status = factory->ort_api .GetEpApi ()->CreateEpDevice (
527+ ep_factory, devices[i], nullptr , ep_options, &ep_device);
528+
529+ factory->ort_api .ReleaseKeyValuePairs (ep_options);
530+
531+ if (status == nullptr ) {
532+ ep_devices[(*num_ep_devices)++] = ep_device;
533+ } else {
534+ return status;
535+ }
536+ }
537+ }
538+
539+ return nullptr ;
540+ }
541+
542+ static OrtStatus* CreateEpImpl (OrtEpFactory* ep_factory,
543+ const OrtHardwareDevice* const * devices,
544+ const OrtKeyValuePairs* const * ep_metadata_pairs,
545+ size_t num_devices,
546+ const OrtSessionOptions* session_options,
547+ const OrtLogger* logger,
548+ OrtEp** ep) noexcept {
549+ if (!ep_factory || !ep) {
550+ return nullptr ;
551+ }
552+ const OpenVINOEpFactory* factory = static_cast <const OpenVINOEpFactory*>(ep_factory);
553+ return factory->ort_api .CreateStatus (ORT_INVALID_ARGUMENT, " OpenVINO EP factory does not support this method." );
554+ }
555+
556+ static void ReleaseEpImpl (OrtEpFactory*, OrtEp*) noexcept {
557+ // no-op as we never create an EP here.
558+ }
559+
560+ const OrtApi& ort_api;
561+ // Intel vendor ID. Refer to the ACPI ID registry (search Intel): https://uefi.org/ACPI_ID_List
562+ static constexpr std::uint32_t intel_vendor_id{0x8086 };
563+ static constexpr const char * const ep_name{kOpenVINOExecutionProvider };
564+ static constexpr const char * const vendor{" Intel Corporation" };
565+ };
566+
446567} // namespace openvino_ep
447568} // namespace onnxruntime
448569
@@ -452,4 +573,37 @@ ORT_API(onnxruntime::Provider*, GetProvider) {
452573 static onnxruntime::openvino_ep::OpenVINO_Provider g_provider;
453574 return &g_provider;
454575}
576+
577+ OrtStatus* CreateEpFactories (const char * /* registration_name*/ , const OrtApiBase* ort_api_base,
578+ OrtEpFactory** factories, size_t max_factories, size_t * num_factories) {
579+ if (!ort_api_base || !factories || !num_factories) {
580+ return nullptr ;
581+ }
582+
583+ const OrtApi* ort_api = ort_api_base->GetApi (ORT_API_VERSION);
584+ if (!ort_api) {
585+ return nullptr ;
586+ }
587+
588+ if (max_factories < 1 ) {
589+ return ort_api->CreateStatus (ORT_INVALID_ARGUMENT,
590+ " Not enough space to return EP factory. Need at least one." );
591+ }
592+
593+ try {
594+ factories[0 ] = new onnxruntime::openvino_ep::OpenVINOEpFactory (*ort_api);
595+ *num_factories = 1 ;
596+ return nullptr ;
597+ } catch (...) {
598+ return ort_api->CreateStatus (ORT_FAIL, " Failed to create OpenVINO EP factory." );
599+ }
600+ }
601+
602+ OrtStatus* ReleaseEpFactory (OrtEpFactory* factory) {
603+ if (factory) {
604+ delete static_cast <onnxruntime::openvino_ep::OpenVINOEpFactory*>(factory);
605+ }
606+ return nullptr ;
607+ }
608+
455609}
0 commit comments