Skip to content

Commit caf528a

Browse files
committed
update: Implement OV Plugin using factories
1 parent a616aba commit caf528a

File tree

2 files changed

+157
-1
lines changed

2 files changed

+157
-1
lines changed

onnxruntime/core/providers/openvino/openvino_provider_factory.cc

Lines changed: 155 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
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"
@@ -19,6 +20,7 @@
1920

2021
namespace onnxruntime {
2122
namespace openvino_ep {
23+
2224
void 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(&params);
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
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
EXPORTS
22
GetProvider
3+
CreateEpFactories
4+
ReleaseEpFactory

0 commit comments

Comments
 (0)