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 | __u32 rsvd; | 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 | * i915_context_engines_load_balance: | 1873 | * i915_context_engines_load_balance: |
| 1811 | * | 1874 | * |
| @@ -1882,6 +1945,61 @@ struct i915_context_engines_bond { · 70 unmodified lines | |||
| 1882 | struct i915_engine_class_instance engines[N__]; \ | 1945 | struct i915_engine_class_instance engines[N__]; \ |
| 1883 | } __attribute__((packed)) name__ | 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 | struct i915_context_param_engines { | 2003 | struct i915_context_param_engines { |
| 1886 | __u64 extensions; /* linked chain of extension blocks, 0 terminates */ | 2004 | __u64 extensions; /* linked chain of extension blocks, 0 terminates */ |
| 1887 | #define I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE 0 /* see i915_context_engines_load_balance */ | 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 | __u8 data[]; | 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 | * struct drm_i915_engine_info | 2567 | * struct drm_i915_engine_info |
| 2380 | * | 2568 | * |