Intel® oneAPI Level Zero Backend Specification

Introduction

This extension introduces a Level Zero backend for Data Parallel C++ (DPC++), which is built on top of Level Zero runtime enabled with the oneAPI Level Zero Specification. The supported targets are Intel GPUs, starting with Gen9.

Note

This specification is a draft. It is not complete or exhaustive in its descriptions. More information, including explanations on mapping the Data Parallel C++ (DPC++) programming model to a Level Zero API, is forthcoming. In the future, it will conform to the SYCL* 2020 spec.

Prerequisites

The Level Zero loader and drivers must be installed on your system for the DPC++ runtime to recognize and enable the Level Zero backend. Visit Intel® oneAPI DPC++/C++ Compiler System Requirements for specific instructions.

User-visible Level Zero Backend Selection and Default Backend

The Level Zero backend is added to the cl::sycl::backend enumeration with:

enum class backend {
  // ...
  level_zero,
  // ...
};

The sections below explain the different ways the Level Zero backend can be selected.

Through an Environment Variable

The SYCL_DEVICE_FILTER environment variable limits the DPC++ runtime to use only a subset of the system's devices. By using level_zero for the backend in SYCL_DEVICE_FILTER, you can select the use of Level Zero as a DPC++ backend. For more information, see the Environment Variables.

Through a Programming API

The Filter Selector extension is described in SYCL* Proposals: Filter Selector. Similar to how the SYCL_DEVICE_FILTER applies filtering to the entire process, this device selector can be used to programmatically select the Level Zero backend.

If the environment variable or filtering device selector is NOT used, the implementation chooses the Level Zero backend for GPU devices that are supported by the installed Level Zero runtime. The serving backend for a DPC++ platform can be queried with the get_backend() member function of the cl::sycl::platform command.

Interoperability with the Level Zero API

The sections below describe the various interoperabilities that are possible between DPC++ and Level Zero. The application must include the following headers to use any of the inter-operation APIs described in this section. These headers must be included in the order shown:

#include "level_zero/ze_api.h"
#include "sycl/backend/level_zero.hpp"

Mapping of DPC++ Objects to Level Zero Handles

These DPC++ objects encapsulate the corresponding Level Zero handles:

DPC++ Object

Level Zero Handle

Platform

ze_driver_handle_t

Device

ze_device_handle_t

Context

ze_context_handle_t

Queue

ze_command_queue_handle_t

Program

ze_module_handle_t

Obtaining Built-in Level Zero Handles from DPC++ Objects

The get_native<cl::sycl::backend::level_zero>() member function is how you can use a raw native Level Zero handle to obtain a specific DPC++ object. The function is supported for the DPC++platform, device, context, queue, event and program classes. You can use a free-function defined in the cl::sycl namespace instead of the member function with:

template <backend BackendName, class SyclObjectT>
auto get_native(const SyclObjectT &Obj) ->
	    typename interop<BackendName, SyclObjectT>::type;

Construct a DPC++ Object from a Level Zero Handle

The following free functions, defined in the cl::sycl::level_zero namespace, allow an application to create a DPC++ object that encapsulates a corresponding Level Zero object:

Level Zero Interoperability Function Description
make<platform>(ze_driver_handle_t);

Constructs a DPC++ platform instance with ze_driver_handle_t.

make<device>(const platform &, ze_device_handle_t);

Constructs a DPC++ device instance with ze_device_handle_t. The platform argument gives a DPC++ platform, which encapsulates a Level Zero driver that supports the passed Level Zero device.

make<context>(const vector_class<device> &, ze_context_handle_t);

Constructs a DPC++ context instance with ze_context_handle_t. The context is created against the devices that are passed in. You must give at least one device and all the devices must be from the same DPC++ platform (from the same Level Zero driver).

make<queue>(const context &, ze_command_queue_handle_t);

Constructs a DPC++ queue instance with ze_command_queue_handle_t. The context argument must be a valid DPC++ context that encapsulates a Level Zero context. The queue is attached to the first device in the passed DPC++ context.

make<program>(const context &, ze_module_handle_t);

Constructs a DPC++ program instance with ze_module_handle_t. The context argument must be a valid DPC++ that encapsulates a Level Zero context. The Level Zero module must be fully linked (example: it does not require further linking through zeModuleDynamicLink) and then the DPC++ program is created in the linked state.

Level Zero Handle Ownership and Thread-safety

The Level Zero runtime does not do reference-counting of its objects, so it is crucial to adhere to these practices of how Level Zero handles are managed: