mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2026-01-26 06:07:53 +00:00
stream: Add DRM device negotiation
A DMA buffer from a DRM device are typically accessed using API related to a DRM device, e.g. Vulkan or EGL. To create such a context for using with a PipeWire stream that passed DRM device DMA buffers applications have so far usually guessed or made use of the same context as the stream content will be presented. This has mostly been the Wayland EGL/Vulkan context, and while this has most of the time worked, it's somewhat by accident, and for reliable operation, PipeWire must be aware of what DRM device a DMA buffer should be accessed using. To address this, introduce device ID negotation, allowing sources and sinks to negotiate what DRM device is supported, and what formats and modifiers are supported by them. This will allow applications to stop relying on luck or the windowing system to figure out how to access the DMA buffers. It also paves the way for being able to use multiple GPUs for different video streams, depending on what the sources and sinks support.
This commit is contained in:
parent
e615f17573
commit
58b958860e
@ -301,5 +301,114 @@ they complete processing the buffer. This can be done in the hardware as part of
|
||||
the render pipeline or explicitly with drmSyncobjTimelineSignal() on the release
|
||||
handle and the release_point of the metadata.
|
||||
|
||||
# Device ID negotation
|
||||
|
||||
The DRM device used for accessing or allocating DMA-BUFs by default undefined. To
|
||||
negotiate what DRM device should be used, and to advertise what DRM device is associated
|
||||
with what combination of format and list of modifiers, device ID negotiation can be
|
||||
performed.
|
||||
|
||||
## Capability discovery
|
||||
|
||||
Device ID negotiation needs explicit support by both end points of a stream, thus, the
|
||||
first step of negotiation is discovering whether other peer has support for it. This is
|
||||
done by advertising a \ref SPA_PARAM_Capability with the key \ref
|
||||
PW_CAPABILITY_DEVICE_ID_NEGOTIATION and value `true`
|
||||
|
||||
```
|
||||
spa_param_dict_build_dict(&b, SPA_PARAM_Capability,
|
||||
&SPA_DICT_ITEMS(
|
||||
SPA_DICT_ITEM(PW_CAPABILITY_DEVICE_ID_NEGOTIATION, "true")));
|
||||
```
|
||||
|
||||
To do this, when connecting to the stream, the \ref PW_STREAM_FLAG_INACTIVE flag must be
|
||||
passed, and a bare minimum video format parameter must be sent. A bare minimum video
|
||||
format parameter must contain a \ref SPA_FORMAT_mediaType with \ref SPA_MEDIA_TYPE_video;
|
||||
\ref SPA_FORMAT_mediaSubtype with \ref SPA_MEDIA_SUBTYPE_raw, \ref SPA_FORMAT_VIDEO_format
|
||||
with something appropriate, and a \ref SPA_FORMAT_VIDEO_size with a rectangle or range of
|
||||
rectangles. For example
|
||||
|
||||
```
|
||||
spa_pod_builder_push_object(&b, &f, SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat);
|
||||
spa_pod_builder_add(&b, SPA_FORMAT_mediaType,
|
||||
SPA_POD_Id (SPA_MEDIA_TYPE_video),
|
||||
0);
|
||||
spa_pod_builder_add(&b, SPA_FORMAT_mediaSubtype,
|
||||
SPA_POD_Id (SPA_MEDIA_SUBTYPE_raw),
|
||||
0);
|
||||
spa_pod_builder_add(&b, SPA_FORMAT_VIDEO_format,
|
||||
SPA_POD_Id(SPA_VIDEO_FORMAT_RGBA),
|
||||
0);
|
||||
spa_pod_builder_add(&b, SPA_FORMAT_VIDEO_size,
|
||||
SPA_POD_CHOICE_RANGE_Rectangle(
|
||||
&SPA_RECTANGLE(320, 240),
|
||||
&SPA_RECTANGLE(1,1),
|
||||
&SPA_RECTANGLE(8192, 8192)),
|
||||
0);
|
||||
params[n_params++] = spa_pod_builder_pop(&b, &f);
|
||||
```
|
||||
|
||||
After having received the first \ref SPA_PARAM_PeerCapability param, if it contained the \ref
|
||||
PW_CAPABILITY_DEVICE_ID set to `true`, the full set of formats can be sent using \ref
|
||||
pw_stream_update_params following by activating the stream using
|
||||
`pw_stream_set_active(stream, true)`.
|
||||
|
||||
Note that the first \ref SPA_PARAM_Format received may be the result of the initial format
|
||||
negotian with bare minimum parameters, and will be superseded by the result of the format
|
||||
negotiation of the later provided format parameters.
|
||||
|
||||
## Device subset capability
|
||||
|
||||
A producer can advertise what devices it's capable of performing device ID negotiation
|
||||
with. This can be used to reduce the amount of devices that are queried for format
|
||||
metadata, which can be a time consuming task, if devices needs to be woken up.
|
||||
|
||||
To achieve this, the consumer adds another \ref SPA_PARAM_PeerCapability item with the key
|
||||
\ref PW_CAPABILITY_DEVICE_IDS set to a string of base 64 encoded `dev_t` device IDs.
|
||||
|
||||
```
|
||||
char *device_ids = ...; /* Base 64 encoding of a dev_t. */.
|
||||
&SPA_DICT_ITEMS(
|
||||
SPA_DICT_ITEM(PW_CAPABILITY_DEVICE_ID_NEGOTIATION, "true"),
|
||||
SPA_DICT_ITEM(PW_CAPABILITY_DEVICE_IDS, device_ids)));
|
||||
```
|
||||
|
||||
## Device ID aware formats
|
||||
|
||||
When both the source and the sink advertises support for device ID negotation, format
|
||||
entries must have a device ID set.
|
||||
|
||||
A device ID is represented as a byte array containing a `dev_t` (see `man 3type dev_t`)
|
||||
device identifier.
|
||||
|
||||
Each format with an associated DRM device (i.e. including all but not only formats with
|
||||
modifiers) must have a \ref SPA_FORMAT_VIDEO_deviceId entry with the \ref
|
||||
SPA_POD_PROP_FLAG_MANDATORY set. E.g.
|
||||
|
||||
```
|
||||
dev_t device_id;
|
||||
|
||||
...
|
||||
|
||||
spa_pod_builder_prop(&b, SPA_FORMAT_VIDEO_deviceId,
|
||||
SPA_POD_PROP_FLAG_MANDATORY);
|
||||
spa_pod_builder_bytes(&b, &device_id, sizeof device_id);
|
||||
```
|
||||
|
||||
## Negotiated device ID
|
||||
|
||||
Once a format is finally negotiated, the resulting device ID is exposed as a \ref
|
||||
SPA_FORMAT_VIDEO_deviceId and may be retrieved by e.g.
|
||||
|
||||
```
|
||||
device_prop = spa_pod_find_prop(format, NULL, SPA_FORMAT_VIDEO_deviceId);
|
||||
spa_pod_parse_object(format,
|
||||
SPA_TYPE_OBJECT_Format, NULL,
|
||||
SPA_FORMAT_VIDEO_deviceId,
|
||||
SPA_POD_OPT_Bytes(&bytes, &size));
|
||||
```
|
||||
|
||||
This device should be used for accessing the associated DMA-BUFs, by e.g. creating a
|
||||
`EGLDisplay` using `EGL_PLATFORM_DEVICE_EXT`.
|
||||
|
||||
*/
|
||||
|
||||
@ -181,6 +181,8 @@ static const struct spa_type_info spa_type_format[] = {
|
||||
{ SPA_FORMAT_VIDEO_H264_alignment, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_H264_BASE "alignment", NULL },
|
||||
|
||||
{ SPA_FORMAT_CONTROL_types, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_CONTROL_BASE "types", spa_type_control },
|
||||
|
||||
{ SPA_FORMAT_VIDEO_deviceId, SPA_TYPE_Bytes, SPA_TYPE_INFO_FORMAT_BASE "deviceId", NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
|
||||
@ -144,6 +144,7 @@ enum spa_format {
|
||||
SPA_FORMAT_VIDEO_H264_alignment, /**< (Id enum spa_h264_alignment) */
|
||||
SPA_FORMAT_VIDEO_H265_streamFormat, /**< (Id enum spa_h265_stream_format) */
|
||||
SPA_FORMAT_VIDEO_H265_alignment, /**< (Id enum spa_h265_alignment) */
|
||||
SPA_FORMAT_VIDEO_deviceId, /**< dev_t identifier (Bytes) */
|
||||
|
||||
/* Image Format keys */
|
||||
SPA_FORMAT_START_Image = 0x30000,
|
||||
|
||||
40
src/pipewire/capabilities.h
Normal file
40
src/pipewire/capabilities.h
Normal file
@ -0,0 +1,40 @@
|
||||
/* PipeWire */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2025 Red Hat */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef PIPEWIRE_CAPABILITIESS_H
|
||||
#define PIPEWIRE_CAPABILITIESS_H
|
||||
|
||||
#include <pipewire/utils.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \defgroup pw_capabilities Capability Names
|
||||
*
|
||||
* A collection of capabilities that can be advertised by end points in
|
||||
* streams.
|
||||
*
|
||||
* \addtogroup pw_capabilities
|
||||
* \{
|
||||
*/
|
||||
|
||||
/**< Link capable of device ID negotiation. The value is either "true" or "false" */
|
||||
#define PW_CAPABILITY_DEVICE_ID_NEGOTIATION "pipewire.device-id-negotiation"
|
||||
/**< Link with device ID negotition capability supports negotiating with
|
||||
* provided list of devices. The value consists of a JSON encoded string array
|
||||
* of base64 encoded dev_t values. */
|
||||
#define PW_CAPABILITY_DEVICE_IDS "pipewire.device-ids"
|
||||
|
||||
#define PW_CAPABILITY_DEVICE_ID "pipewire.device-id" /**< Link capable of device Id negotation */
|
||||
|
||||
/** \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* PIPEWIRE_CAPABILITIES_H */
|
||||
@ -45,6 +45,7 @@ pipewire_headers = [
|
||||
'type.h',
|
||||
'utils.h',
|
||||
'work-queue.h',
|
||||
'capabilities.h',
|
||||
]
|
||||
|
||||
pipewire_sources = [
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user