A little bit of documentation covering the topics of engine discovery, context engine maps and virtual engines. It is not very detailed but supposed to be a starting point of giving a brief high level overview of general principles and intended use cases. v2: * Have the text in uapi header and link from there. v4: * Link from driver-uapi.rst.
Showing the changes to include/uapi (1 of 2 files). Show all
Unified · Split
| @@ -1806,6 +1806,69 @@ struct drm_i915_gem_context_param_sseu { · 1805 unmodified lines | ||
| 1806 | 1806 | __u32 rsvd; |
| 1807 | 1807 | }; |
| 1808 | 1808 | |
| 1809 | +/** | |
| 1810 | + * DOC: Virtual Engine uAPI | |
| 1811 | + * | |
| 1812 | + * Virtual engine is a concept where userspace is able to configure a set of | |
| 1813 | + * physical engines, submit a batch buffer, and let the driver execute it on any | |
| 1814 | + * engine from the set as it sees fit. | |
| 1815 | + * | |
| 1816 | + * This is primarily useful on parts which have multiple instances of a same | |
| 1817 | + * class engine, like for example GT3+ Skylake parts with their two VCS engines. | |
| 1818 | + * | |
| 1819 | + * For instance userspace can enumerate all engines of a certain class using the | |
| 1820 | + * previously described `Engine Discovery uAPI`_. After that userspace can | |
| 1821 | + * create a GEM context with a placeholder slot for the virtual engine (using | |
| 1822 | + * `I915_ENGINE_CLASS_INVALID` and `I915_ENGINE_CLASS_INVALID_NONE` for class | |
| 1823 | + * and instance respectively) and finally using the | |
| 1824 | + * `I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE` extension place a virtual engine in | |
| 1825 | + * the same reserved slot. | |
| 1826 | + * | |
| 1827 | + * Example of creating a virtual engine and submitting a batch buffer to it: | |
| 1828 | + * | |
| 1829 | + * .. code-block:: C | |
| 1830 | + * | |
| 1831 | + * I915_DEFINE_CONTEXT_ENGINES_LOAD_BALANCE(virtual, 2) = { | |
| 1832 | + * .base.name = I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE, | |
| 1833 | + * .engine_index = 0, // Place this virtual engine into engine map slot 0 | |
| 1834 | + * .num_siblings = 2, | |
| 1835 | + * .engines = { { I915_ENGINE_CLASS_VIDEO, 0 }, | |
| 1836 | + * { I915_ENGINE_CLASS_VIDEO, 1 }, }, | |
| 1837 | + * }; | |
| 1838 | + * I915_DEFINE_CONTEXT_PARAM_ENGINES(engines, 1) = { | |
| 1839 | + * .engines = { { I915_ENGINE_CLASS_INVALID, | |
| 1840 | + * I915_ENGINE_CLASS_INVALID_NONE } }, | |
| 1841 | + * .extensions = to_user_pointer(&virtual), // Chains after load_balance extension | |
| 1842 | + * }; | |
| 1843 | + * struct drm_i915_gem_context_create_ext_setparam p_engines = { | |
| 1844 | + * .base = { | |
| 1845 | + * .name = I915_CONTEXT_CREATE_EXT_SETPARAM, | |
| 1846 | + * }, | |
| 1847 | + * .param = { | |
| 1848 | + * .param = I915_CONTEXT_PARAM_ENGINES, | |
| 1849 | + * .value = to_user_pointer(&engines), | |
| 1850 | + * .size = sizeof(engines), | |
| 1851 | + * }, | |
| 1852 | + * }; | |
| 1853 | + * struct drm_i915_gem_context_create_ext create = { | |
| 1854 | + * .flags = I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS, | |
| 1855 | + * .extensions = to_user_pointer(&p_engines); | |
| 1856 | + * }; | |
| 1857 | + * | |
| 1858 | + * ctx_id = gem_context_create_ext(drm_fd, &create); | |
| 1859 | + * | |
| 1860 | + * // Now we have created a GEM context with its engine map containing a | |
| 1861 | + * // single virtual engine. Submissions to this slot can go either to | |
| 1862 | + * // vcs0 or vcs1, depending on the load balancing algorithm used inside | |
| 1863 | + * // the driver. The load balancing is dynamic from one batch buffer to | |
| 1864 | + * // another and transparent to userspace. | |
| 1865 | + * | |
| 1866 | + * ... | |
| 1867 | + * execbuf.rsvd1 = ctx_id; | |
| 1868 | + * execbuf.flags = 0; // Submits to index 0 which is the virtual engine | |
| 1869 | + * gem_execbuf(drm_fd, &execbuf); | |
| 1870 | + */ | |
| 1871 | + | |
| 1809 | 1872 | /* |
| 1810 | 1873 | * i915_context_engines_load_balance: |
| 1811 | 1874 | * |
| @@ -1882,6 +1945,61 @@ struct i915_context_engines_bond { · 70 unmodified lines | ||
| 1882 | 1945 | struct i915_engine_class_instance engines[N__]; \ |
| 1883 | 1946 | } __attribute__((packed)) name__ |
| 1884 | 1947 | |
| 1948 | +/** | |
| 1949 | + * DOC: Context Engine Map uAPI | |
| 1950 | + * | |
| 1951 | + * Context engine map is a new way of addressing engines when submitting batch- | |
| 1952 | + * buffers, replacing the existing way of using identifiers like `I915_EXEC_BLT` | |
| 1953 | + * inside the flags field of `struct drm_i915_gem_execbuffer2`. | |
| 1954 | + * | |
| 1955 | + * To use it created GEM contexts need to be configured with a list of engines | |
| 1956 | + * the user is intending to submit to. This is accomplished using the | |
| 1957 | + * `I915_CONTEXT_PARAM_ENGINES` parameter and `struct | |
| 1958 | + * i915_context_param_engines`. | |
| 1959 | + * | |
| 1960 | + * For such contexts the `I915_EXEC_RING_MASK` field becomes an index into the | |
| 1961 | + * configured map. | |
| 1962 | + * | |
| 1963 | + * Example of creating such context and submitting against it: | |
| 1964 | + * | |
| 1965 | + * .. code-block:: C | |
| 1966 | + * | |
| 1967 | + * I915_DEFINE_CONTEXT_PARAM_ENGINES(engines, 2) = { | |
| 1968 | + * .engines = { { I915_ENGINE_CLASS_RENDER, 0 }, | |
| 1969 | + * { I915_ENGINE_CLASS_COPY, 0 } } | |
| 1970 | + * }; | |
| 1971 | + * struct drm_i915_gem_context_create_ext_setparam p_engines = { | |
| 1972 | + * .base = { | |
| 1973 | + * .name = I915_CONTEXT_CREATE_EXT_SETPARAM, | |
| 1974 | + * }, | |
| 1975 | + * .param = { | |
| 1976 | + * .param = I915_CONTEXT_PARAM_ENGINES, | |
| 1977 | + * .value = to_user_pointer(&engines), | |
| 1978 | + * .size = sizeof(engines), | |
| 1979 | + * }, | |
| 1980 | + * }; | |
| 1981 | + * struct drm_i915_gem_context_create_ext create = { | |
| 1982 | + * .flags = I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS, | |
| 1983 | + * .extensions = to_user_pointer(&p_engines); | |
| 1984 | + * }; | |
| 1985 | + * | |
| 1986 | + * ctx_id = gem_context_create_ext(drm_fd, &create); | |
| 1987 | + * | |
| 1988 | + * // We have now created a GEM context with two engines in the map: | |
| 1989 | + * // Index 0 points to rcs0 while index 1 points to bcs0. Other engines | |
| 1990 | + * // will not be accessible from this context. | |
| 1991 | + * | |
| 1992 | + * ... | |
| 1993 | + * execbuf.rsvd1 = ctx_id; | |
| 1994 | + * execbuf.flags = 0; // Submits to index 0, which is rcs0 for this context | |
| 1995 | + * gem_execbuf(drm_fd, &execbuf); | |
| 1996 | + * | |
| 1997 | + * ... | |
| 1998 | + * execbuf.rsvd1 = ctx_id; | |
| 1999 | + * execbuf.flags = 1; // Submits to index 0, which is bcs0 for this context | |
| 2000 | + * gem_execbuf(drm_fd, &execbuf); | |
| 2001 | + */ | |
| 2002 | + | |
| 1885 | 2003 | struct i915_context_param_engines { |
| 1886 | 2004 | __u64 extensions; /* linked chain of extension blocks, 0 terminates */ |
| 1887 | 2005 | #define I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE 0 /* see i915_context_engines_load_balance */ |
| @@ -2375,6 +2493,76 @@ struct drm_i915_query_topology_info { · 487 unmodified lines | ||
| 2375 | 2493 | __u8 data[]; |
| 2376 | 2494 | }; |
| 2377 | 2495 | |
| 2496 | +/** | |
| 2497 | + * DOC: Engine Discovery uAPI | |
| 2498 | + * | |
| 2499 | + * Engine discovery uAPI is a way of enumerating physical engines present in a | |
| 2500 | + * GPU associated with an open i915 DRM file descriptor. This supersedes the old | |
| 2501 | + * way of using `DRM_IOCTL_I915_GETPARAM` and engine identifiers like | |
| 2502 | + * `I915_PARAM_HAS_BLT`. | |
| 2503 | + * | |
| 2504 | + * The need for this interface came starting with Icelake and newer GPUs, which | |
| 2505 | + * started to establish a pattern of having multiple engines of a same class, | |
| 2506 | + * where not all instances were always completely functionally equivalent. | |
| 2507 | + * | |
| 2508 | + * Entry point for this uapi is `DRM_IOCTL_I915_QUERY` with the | |
| 2509 | + * `DRM_I915_QUERY_ENGINE_INFO` as the queried item id. | |
| 2510 | + * | |
| 2511 | + * Example for getting the list of engines: | |
| 2512 | + * | |
| 2513 | + * .. code-block:: C | |
| 2514 | + * | |
| 2515 | + * struct drm_i915_query_engine_info *info; | |
| 2516 | + * struct drm_i915_query_item item = { | |
| 2517 | + * .query_id = DRM_I915_QUERY_ENGINE_INFO; | |
| 2518 | + * }; | |
| 2519 | + * struct drm_i915_query query = { | |
| 2520 | + * .num_items = 1, | |
| 2521 | + * .items_ptr = (uintptr_t)&item, | |
| 2522 | + * }; | |
| 2523 | + * int err, i; | |
| 2524 | + * | |
| 2525 | + * // First query the size of the blob we need, this needs to be large | |
| 2526 | + * // enough to hold our array of engines. The kernel will fill out the | |
| 2527 | + * // item.length for us, which is the number of bytes we need. | |
| 2528 | + * // | |
| 2529 | + * // Alternatively a large buffer can be allocated straight away enabling | |
| 2530 | + * // querying in one pass, in which case item.length should contain the | |
| 2531 | + * // length of the provided buffer. | |
| 2532 | + * err = ioctl(fd, DRM_IOCTL_I915_QUERY, &query); | |
| 2533 | + * if (err) ... | |
| 2534 | + * | |
| 2535 | + * info = calloc(1, item.length); | |
| 2536 | + * // Now that we allocated the required number of bytes, we call the ioctl | |
| 2537 | + * // again, this time with the data_ptr pointing to our newly allocated | |
| 2538 | + * // blob, which the kernel can then populate with info on all engines. | |
| 2539 | + * item.data_ptr = (uintptr_t)&info, | |
| 2540 | + * | |
| 2541 | + * err = ioctl(fd, DRM_IOCTL_I915_QUERY, &query); | |
| 2542 | + * if (err) ... | |
| 2543 | + * | |
| 2544 | + * // We can now access each engine in the array | |
| 2545 | + * for (i = 0; i < info->num_engines; i++) { | |
| 2546 | + * struct drm_i915_engine_info einfo = info->engines[i]; | |
| 2547 | + * u16 class = einfo.engine.class; | |
| 2548 | + * u16 instance = einfo.engine.instance; | |
| 2549 | + * .... | |
| 2550 | + * } | |
| 2551 | + * | |
| 2552 | + * free(info); | |
| 2553 | + * | |
| 2554 | + * Each of the enumerated engines, apart from being defined by its class and | |
| 2555 | + * instance (see `struct i915_engine_class_instance`), also can have flags and | |
| 2556 | + * capabilities defined as documented in i915_drm.h. | |
| 2557 | + * | |
| 2558 | + * For instance video engines which support HEVC encoding will have the | |
| 2559 | + * `I915_VIDEO_CLASS_CAPABILITY_HEVC` capability bit set. | |
| 2560 | + * | |
| 2561 | + * Engine discovery only fully comes to its own when combined with the new way | |
| 2562 | + * of addressing engines when submitting batch buffers using contexts with | |
| 2563 | + * engine maps configured. | |
| 2564 | + */ | |
| 2565 | + | |
| 2378 | 2566 | /** |
| 2379 | 2567 | * struct drm_i915_engine_info |
| 2380 | 2568 | * |