GFX is an experimental OpenVINO device plugin that compiles an ov::Model
into a stage-based GPU execution pipeline. The module lives as a standalone
OpenVINO contrib module and builds against an OpenVINO Developer Package.
The current implementation has two backend families:
metal: macOS execution through Metal, Apple MPS/MPSGraph vendor primitives, MPSRT runtime-model records, and generated MSL custom kernels.opencl: non-Apple execution through a dynamically loaded OpenCL runtime, optional bundled CLVK/CLSPV deployment support, and manifest-backed source-kernel artifacts.
Unsupported models fail during compile_model() or support probing. The plugin
does not silently fall back to CPU for intermediate execution.
Read these files first:
docs/ARCHITECTURE.md: current pipeline, runtime, MLIR, and backend splitdocs/DEVELOPMENT.md: build flow and development rulesdocs/TESTING.md: test targets, compare tooling, and validation strategydocs/USAGE.md: public properties, backend selection, and profiling usage
- Device name:
GFX - Runtime backends:
metal,opencl - Build-time backend options:
GFX_ENABLE_METAL,GFX_ENABLE_OPENCL - Runtime backend property:
GFX_BACKEND=metal|opencl - Default backend:
GFX_DEFAULT_BACKEND=auto|metal|opencl - Raspberry/OpenCL bundle option:
GFX_ENABLE_RASPBERRY_OPENCL_TOOLCHAIN - OpenCL is disabled by CMake on macOS; the Apple route is Metal/MPS/MPSRT/MSL.
- On non-Apple builds,
autoresolves to OpenCL when the source backend is enabled in the build. - Explicit default backend requests are strict: CMake fails when the requested backend is unavailable instead of selecting another backend.
query_model()uses the same backend-aware support path as compilation.- OpenVINO compiled-model cache round-trip is currently not exposed:
ov::cache_dir,export_model(), andimport_model()fail throughsrc/plugin/compiled_model_cache_contract.hpp. - The compiler has an internal serialized
CacheEnvelopewire/store/load contract for manifest, artifact descriptor, payload identity, and stable-key validation. It is not a public OpenVINO cache format and does not import a full backend executable bundle yet. GfxRemoteContextandGfxRemoteTensorexist; practical capabilities depend on the selected backend.
include/openvino/gfx_plugin/: public plugin headers and property namessrc/common/: backend ids, configured-backend availability values, artifact-payload interfaces, activation/bias metadata, dispatch and parallelism value types, submit-policy records, constant-evaluation helpers, and device-family/profile value types shared by compiler, runtime, and backend codesrc/compiler/: backend target registry, backend capability records, operation support policies, backend stage-placement contracts, tensor-layout classification, stage compiler policy, lowering-plan construction, pipeline-stage descriptor building, fusion selection, compiler-side pipeline-stage I/O planning, memory planning, manifest/cache-envelope building, executable-bundle assembly, runtime executable descriptor build/verification, backend-module construction, and artifact payload routing used by query and compilationsrc/plugin/: OpenVINO-facingPlugin,CompiledModel, infer-request API glue, properties, disabled compiled-model cache/import/export entry points, backend selection, backend-access helpers, and variable-state OpenVINO API objectssrc/runtime/: backend-neutral stage interfaces, submission planning, profiling report assembly, runtime executable descriptor records, runtime pipeline-stage plans, runtime sessions, backend runtime/provider interfaces, backend request state, backend stage factory interfaces, infer pipeline/executor/submission helpers, stateful runtime helpers, pipeline-stage materialization, fused-output lifetime planning, liveness-aware output workspaces, remote context/tensor helpers, descriptor-backed view-only stages, tensor binding contract helpers, descriptor-owned runtime-parameter and const-tensor payload materialization, runtime-value and kernel-launch planning, and target profilessrc/kernel_ir/: backend-neutral kernel manifests, custom-kernel family metadata, cache keys, dispatch descriptions, embedded Metal/OpenCL helper sources, and OpenCL source artifactssrc/mlir/: support probing, OpenVINO-node lowering, pass helpers, backend stage hooks, MPSRT dialect/metadata helpers, and generic MLIR kernel construction used by backend compiler routessrc/backends/metal/: Metal plugin glue, Objective-C++ runtime, memory management, profiling, backend compiler module, Apple MSL/MPS/MPSRT source planning, shared MPSRT ABI records, MPSRT vendor primitive contracts, MSL compilation, runtime kernel loading, MPSRT preparation, descriptor-backed vendor primitive stages, and MPS/MPSGraph vendor primitive executionsrc/backends/opencl/: OpenCL plugin glue, dynamic API loader, buffer manager, backend compiler policy, backend-owned source-artifact payload materialization, program cache, memory ops, runtime kernel loading, and generic source-artifact executionsrc/transforms/: OpenVINO graph rewrites, fusion passes, and layout cleanuptests/: unit, functional, backend, integration, compare, executable gtest-matrix, and microbench coveragebench/: optional local/remote evaluation helperstools/: profiling and microbench post-processing helpersthird_party/llvm-project/: vendored LLVM/MLIR used by the buildthird_party/clvk/,third_party/clspv/: optional submodules used by the Raspberry/OpenCL bundle flow whenGFX_ENABLE_RASPBERRY_OPENCL_TOOLCHAINis enabled
The high-level path is:
Plugin::compile_model()parses properties and resolvesGFX_BACKEND.src/compiler/BackendRegistryresolves one of the backend compiler modules available in the current configured build. The module owns the immutableBackendTarget, backend-owned transformPipelineOptions, fusion capabilities, post-op fusion capabilities, stage-placement policy, source kernel dispatch policy, and artifact payload resolver. Default backend modules are built bysrc/compiler/backend_module_provider.*and backend-specific*_backend_module.*files.GfxCompilerServiceruns backend-aware transforms, operation support checks, lowering-plan creation, memory-plan creation, manifest building, executable-bundle assembly, cache-envelope construction, and artifact payload materialization.CompiledModelaskssrc/compiler/runtime_executable_descriptor_builder.*to build and verify aRuntimeExecutableDescriptorfrom the compiler executable bundle. The runtimePipelineStageRuntimePlanused for stage materialization is a separate compiler output, not part of the cacheable descriptor. The internalCacheEnvelopecan be serialized and stored for stable-key validation, but native compiled-model cache round-trip APIs remain disabled until a complete public executable-bundle import/export path exists. The old OpenVINO-model serialization path is disabled bysrc/plugin/compiled_model_cache_contract.hpp.CompiledModel::build_op_pipeline()consumes the compiler-owned runtime stage plan and descriptor, then delegates concrete stage materialization tosrc/runtime/pipeline_stage_materializer.*. The compiler stage builder usessrc/compiler/pipeline_stage_plan.*for model-output flags, input links, and output aliases,src/compiler/pipeline_stage_fusion.*for fusion selection, and emits runtime-facing plans insrc/runtime/pipeline_stage_plan.hpp.- Pipeline records are
PipelineStageDescvalues fromsrc/runtime/pipeline_stage_desc.hpp. Fused output lifetimes are derived from runtime memory contracts insrc/runtime/fused_output_lifetime_plan.*.src/runtime/tensor_binding_contract.*parses descriptor-owned tensor type/shape contracts and identifies the generated source families whoseRuntimeParamspayload can be materialized without anov::Node. Current descriptor-ownedRuntimeParamscoverage includes Broadcast, binary elementwise broadcast, Select, Tile, Softmax/LogSoftmax, Transpose, and Reduce families when the required static tensor contracts and metadata are present. src/compiler/stage_policy.*selects fusion, precision, submit policy, and other shared stage traits. The selected backendStagePlacementPolicy,PostOpFusionCapabilities, and source-kernel dispatch policy are passed throughGpuStageRuntimeOptions/compiler::StageCompilerPolicy; stages must not resolve the global backend registry at request time.src/mlir/lowers supported nodes and exposes backend hooks; Metal and OpenCL source/vendor payload planning lives in the matchingsrc/backends/*/compiler/directory.- Runtime backend providers in
src/runtime/backend_runtime_provider.*create the selectedBackendStateand dispatch infer execution to the active backend. The active backend creates descriptor-backed view-only stages or concrete backendGpuStageobjects throughBackendStageFactory. - Infer requests create a
RuntimeSession, bind host or remote tensors against descriptor memory-region contracts, prepare kernel executables per request, allocate or reuse backend buffers, execute submission windows, and collect profiling data.
The pipeline is intentionally stage-based. Fused stages, descriptor-backed view-only stages, view-style split outputs, stateful variable buffers, reusable host outputs, prepared binding caches, immutable const caches, and workspace-managed intermediate outputs all live in the shared runtime/plugin layer instead of being duplicated per backend. Runtime stages do not own tensor-view or output-lifetime classification; that metadata comes from compiler/runtime descriptors.
The compiler layer is the public architecture boundary between OpenVINO graph
semantics and runtime execution. Do not add new support checks directly in
Plugin or backend request code when the same decision belongs in
src/compiler/.
Backend stage creation is descriptor-owned. Stages that need a kernel, source
artifact, vendor descriptor, or ABI metadata must consume the matching
RuntimeStageExecutableDescriptor; request-time code must not reconstruct
payloads from the OpenVINO node.
Source-node bridge routes are not allowed. Vendor primitive metadata,
runtime-shape arguments, ConstTensor source ABI, and source RuntimeParams
roles must be represented by descriptor-owned payloads and validation
contracts; if the compiler cannot freeze that data, the route must fail
descriptor verification instead of falling back to request-time ov::Node
inspection.
There is no generic backend-lowering escape route. Metal and OpenCL operation support must resolve to common metadata, an explicit generated kernel unit, a vendor primitive, or a consciously documented backend route.
The Metal backend is the Apple production path. It combines:
- Apple MPS/MPSGraph vendor primitives for selected Conv2D, GroupConv, Pool, Resize, MatMul/GEMM, Softmax, TopK, and attention-style stages
- Apple MSL custom kernels for general elementwise, layout, reduction, shape, slice, scatter/gather, RoPE, RMS, compressed MatMul, and SDPA helper paths
- backend compiler policy, generated MSL artifact payloads, and MPS/MPSGraph
vendor descriptor payloads under
src/backends/metal/compiler/ - shared MPSRT ABI and builder records under
src/backends/metal/common/mpsrt/ - MPSRT runtime-model construction and request encoding under
src/backends/metal/runtime/mpsrt/ - embedded MPSRT helper kernels under
src/kernel_ir/metal_kernels/ - Objective-C++ request-time execution under
src/backends/metal/runtime/
Metal placement is selected by the Metal compiler stage-placement policy and consumed by shared stage policy. Do not bypass those contracts with ad-hoc backend switches when adding new Metal routes.
Compiler-owned Metal payloads currently cover generated MSL units such as
ShapeOf, Range, Tile, Concat, Split, Slice, activation, elementwise,
Transpose, numeric and logical reduction, Softmax/LogSoftmax, and causal SDPA
helper forms. MPS/MPSGraph vendor descriptor payloads are consumed by the
MpsrtVendorPrimitive runtime stage for supported MatMul/GEMM, last-axis
Softmax, Pool2D, Resize2D, and SDPA forms. Vendor selection remains
contract-limited: if the descriptor, storage, or external-buffer ABI cannot be
built, the route must be rejected or use another supported current route.
Pooling on Metal requires a valid MPS-family vendor route; the removed generic
MSL Pool2D fallback must not be reintroduced as an unvalidated path.
The OpenCL backend is the current non-Apple route. It loads OpenCL dynamically
at runtime and executes source artifacts described by
src/kernel_ir/gfx_opencl_source_artifacts.*.
OpenCL source payload materialization is owned by
src/backends/opencl/compiler/opencl_kernel_artifacts.* and registered through
the backend module. The common executable-bundle builder records artifact
descriptors and requires the selected backend to provide payloads for executable
OpenCL source routes.
OpenCL artifacts are role-based. Source id, entry point, local size, tensor
roles, scalar ABI, runtime-shape scalars, constant materialization, boolean
buffer padding, static u32/f32 scalar payloads, and generated Concat/Split
chunk helpers should stay in the artifact manifest rather than being
reimplemented in infer-request code.
Routes that need runtime shape arguments must set
KernelUnit::requires_runtime_shape_args; infer requests consume the resulting
manifest/runtime-descriptor flag instead of special-casing the OpenCL backend.
Backend operation support and kernel-unit registration live under
src/backends/opencl/compiler/; runtime loading and enqueue stay under
src/backends/opencl/runtime/.
Embedded OpenCL source units live under src/kernel_ir/opencl_kernels/.
Current generated units include activation, elementwise, f32 MatMul,
f32 Conv2D/GroupConv2D, f32/f16 Interpolate, f32 reduction, boolean reduction,
f32/f16 Softmax, dynamic-static-rank f32/f16 Softmax, f32/f16 Pool2D,
f32/f16/i64 Range, ShapeOf, Tile, Transpose, logical-bool elementwise,
compare/select, and generated Concat/Split helpers.
There is no active handwritten OpenCL kernel-unit exception in the current
registry.
Family-specific OpenCL compiler adapters such as
opencl_conv_kernel_unit.*, opencl_pool_kernel_unit.*,
opencl_range_kernel_unit.*, opencl_softmax_kernel_unit.*, and
opencl_tile_kernel_unit.* resolve generated KernelUnit records and
materialize source payloads. Keep new family routes in those backend compiler
adapters instead of adding special cases to request-time execution.
The OpenCL compiler registry requires an explicit kernel unit for generated
routes; there is no generic MLIR fallback for OpenCL operation support.
Unsupported modes, axes, padding, shapes, or element types fail during support
probing instead of falling through to a hidden runtime path.
Generated activation artifacts cover the shared unary activation family and
carry op-specific scalar payloads in the manifest. Swish supports the default
beta, a scalar constant beta, and a runtime scalar beta tensor through the
opencl/generated/activation_runtime_beta_* units when shape and type contracts
match.
On Linux/Raspberry-style deployments, the build can stage a plugin-local OpenCL
bundle from third_party/clvk and third_party/clspv. The runtime loader checks
plugin-local opencl/, clvk/, and plugin directories before system/vendor
OpenCL libraries and configures CLVK tool paths when bundled tools are present.
MLIR is shared infrastructure, not a separate backend object. It is used for:
- support probing through
mlir_supports_node() - node lowering through
mlir_builder_*.cpp - pass and cleanup utilities
- backend hooks consumed by Metal and OpenCL compiler modules
- typed MPSRT dialect/metadata helpers shared with the Metal compiler path
Backend-specific source planning is no longer described as generic MLIR
ownership. Apple MSL/MPS source planning and typed MPSRT builder-plan assembly
live under src/backends/metal/compiler/; OpenCL source-artifact payload
materialization lives under src/backends/opencl/compiler/. Runtime-value
payload planning for dynamic shapes and source artifacts is shared runtime code
under src/runtime/gfx_stage_runtime_values.*.
Activation lowering keeps OpenCL and Metal source plans on the same operation
contract. Swish beta is represented either as a static scalar payload or as a
second scalar tensor input when the runtime-beta path is supported.
Convolution lowering is family-owned. Metal Conv2D and GroupConv2D use descriptor-backed MPS vendor routes when the external-buffer ABI contract can be built. OpenCL generated Conv2D/GroupConv2D covers f32 static 4D NCHW data/output with constant weights, 2D stride/dilation/padding metadata, and explicit generated kernel units.
Reduction lowering uses the same source-plan boundary. Numeric reductions cover the current f32 generated-kernel contract; logical reductions cover the current boolean contract. Both require static input/output shapes and constant axes.
Softmax lowering is family-owned for Softmax and LogSoftmax on Metal. The
generated Metal units cover f32/f16 static-shape Softmax and LogSoftmax with
runtime-parameter binding. OpenCL currently covers Softmax f32/f16 static
shapes and dynamic-output shapes with static rank; OpenCL LogSoftmax is not a
current source-artifact route.
Pooling lowering is family-owned for MaxPool and AvgPool. OpenCL generated
Pool2D units cover f32/f16 static 4D NCHW input/output shapes with 2D kernel,
stride, dilation, and padding metadata. Metal Pool2D uses the MPS vendor route
only when the descriptor and external-buffer ABI are valid.
When adding or changing an op, keep support probing, lowering, backend source planning, runtime binding, and tests on the same contract.
The current compiler service does not serialize a native backend executable
cache. It constructs a manifest/executable bundle for the selected backend,
builds a serialized CacheEnvelope contract for identity validation, and the
runtime consumes the executable descriptor during stage creation.
export_model() and import_model() are currently not implemented because the
public OpenVINO cache path still lacks full executable-bundle import/export and
backend-payload materialization.
Compiler-owned tensor layout classification lives in
src/compiler/tensor_layout.*; shared stage policy consumes the resulting
layout contract instead of reclassifying view-only or materialized layout ops.
Runtime tensor binding contract helpers live in
src/runtime/tensor_binding_contract.*; do not duplicate their element-type,
static-shape, or generated RuntimeParams ownership rules in Metal/OpenCL
request-time code.
Coverage is shape- and backend-dependent. The active code contains support for:
- Conv2D, Conv3D, GroupConv, MatMul
- Add, Sub, Mul, Div, Pow, Mod, FloorMod
- compare, logical, Select, unary activation, and elementwise transforms
- RMS, RoPE, Softmax, reductions, BatchNormInference
- MaxPool, AvgPool, Interpolate
- Concat, Split, VariadicSplit, Slice, StridedSlice-style paths, Transpose, Reshape, Convert, ShapeOf, Range, Tile
- Gather, GatherND, GatherElements, ScatterUpdate, ScatterElementsUpdate, ScatterNDUpdate, TopK, SpaceToDepth, DepthToSpace
- stateful graph behavior through
ReadValue/Assign - selected Metal attention paths, including compiler-owned MPSGraph-backed vendor SDPA artifacts and fused causal-mask attention forms
Important constraints:
- Many paths require static rank or static shape.
- Many ops require constant attributes.
- Backend parity is not automatic between Metal and OpenCL.
- Unsupported shapes or types should fail clearly instead of falling back.
Configure against an OpenVINO Developer Package:
cmake -S . -B build-gfx-plugin -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DOpenVINODeveloperPackage_DIR=/path/to/openvino/install/cmake \
-DENABLE_TESTS=ON \
-DGFX_DEFAULT_BACKEND=autoBuild the plugin and common test tools:
cmake --build build-gfx-plugin --target openvino_gfx_plugin
cmake --build build-gfx-plugin --target ov_gfx_func_tests ov_gfx_unit_tests ov_gfx_runtime_micro_tests
cmake --build build-gfx-plugin --target ov_gfx_compare_runner ov_gfx_microbenchUseful options:
-DGFX_ENABLE_METAL=ON|OFF-DGFX_ENABLE_OPENCL=ON|OFF-DGFX_ENABLE_RASPBERRY_OPENCL_TOOLCHAIN=ON|OFF-DGFX_RASPBERRY_OPENCL_BUNDLE_DIR=<path>-DGFX_DEFAULT_BACKEND=auto|metal|opencl-DENABLE_TESTS=ON|OFF
GFX_DEFAULT_BACKEND=auto must resolve to an available backend. Explicit
metal or opencl requests are configure-time requirements and fail when that
backend is unavailable in the current build.
Run the module test label:
ctest --test-dir build-gfx-plugin --output-on-failure -L GFXRun focused tests directly:
find build-gfx-plugin -name ov_gfx_unit_tests -type f
DYLD_LIBRARY_PATH=/path/to/openvino/runtime/libs \
<path-to-ov_gfx_unit_tests> --gtest_filter=GfxStagePolicy.*Use ov_gfx_compare_runner for accuracy triage and ov_gfx_microbench for
profiling/microbench triage. Do not use microbench output as correctness
evidence, and do not use compare-runner timing as performance evidence.
The test CMake flow uses tests/tools/gfx_gtest_matrix.py to capture
--gtest_list_tests from real GFX test binaries and compare executable test
matrices. gfx_gtest_matrix_compare is fail-closed: it requires explicit
GFX_GTEST_MATRIX_REFERENCE_ROOTS for cross-target comparisons, and cross-build
host capture fails unless an emulator is configured. Do not use
source/file/string-presence checks as test readiness or architecture evidence;
use executed contract coverage, route coverage, conformance tests, and
profiling evidence instead.
- Add or update support probing in
src/mlir/. - Update the backend operation support policy and route selection under
src/compiler/orsrc/backends/*/compiler/when the supported route changes. - Add MLIR lowering or a transform in the appropriate
src/mlir/orsrc/transforms/file. - Choose the shared runtime contract first: stage policy, kernel manifest, compiler tensor-layout plan, compiler pipeline-stage builder/fusion plan, compiler pipeline-stage I/O plan, runtime stage materializer, compiler memory plan, fused-output lifetime plan, compiler-owned runtime executable descriptor builder, runtime stage plan, runtime-value payloads, OpenCL artifact metadata, or Metal MPSRT/Apple MSL source planning under the backend compiler directory.
- Add backend-specific code only under
src/backends/metal/orsrc/backends/opencl/when the shared path cannot express the behavior. - Add focused unit tests first, then backend or functional coverage when the behavior is externally visible.
- Update this README and the relevant file under
docs/when supported shapes, public properties, runtime routing, profiling, or test workflows change.
- Keep shared behavior in
src/plugin/,src/runtime/,src/kernel_ir/, orsrc/mlir/; keep compiler contracts insrc/compiler/; keep backend-only code under the matching backend directory. - Do not add CPU fallback for unsupported GPU stages.
- Do not add runtime switches to preserve obsolete execution routes.
- Do not duplicate OpenCL artifact ABI rules in request code.
- Do not bypass backend stage-placement policies through one-off MPS/MSL/OpenCL selection logic.
- Do not move pipeline descriptor construction or fusion selection back into
CompiledModelor backend request code; keep descriptor construction insrc/compiler/pipeline_stage_builder.*and fusion selection insrc/compiler/pipeline_stage_fusion.*. - Do not reintroduce the deleted standalone
src/backends/metal/runtime/mps_graph_attention_stage.*; MPSGraph attention is represented by compiler-owned vendor artifacts and MPSRT vendor primitive execution. - Do not bypass
GfxCompilerService,ManifestBundle, orExecutableBundlewith ad-hoc backend support checks. - Do not reintroduce
BackendLowering,metal_lowering, or source-signature scanning fallbacks. Generated/prebuilt kernels must carry compiler-owned manifest ABI metadata. - Do not modify
third_party/llvm-project/unless the task explicitly requires vendored LLVM/MLIR changes. Keepthird_party/clvkandthird_party/clspvas reviewed submodule gitlinks, not copied source trees. - Keep local artifacts, build trees, sensitive access material, machine names, and agent notes out of commits.
Enable profiling through standard OpenVINO profiling and GFX-specific report properties:
ov::enable_profilingGFX_PROFILING_LEVELGFX_PROFILING_REPORTGFX_MEM_STATS
The profiling JSON includes compile and infer sections, target-profile counters
such as target_backend_metal and target_backend_opencl, stage estimates such
as bytes moved and MAC/FLOP counts, and backend-specific Metal/OpenCL segments
when available. Backend trace exporters are registered through the shared trace
sink registry; the Metal backend currently registers signpost and
os_signpost. See docs/PROFILING_RUNBOOK.md and
docs/MICROBENCH_SCHEMA.md.