Align to newest protocol revision

ext-screencopy-v1
Andri Yngvason 2024-03-24 16:25:42 +00:00
parent 610d69fae0
commit 9a3bdbfdbe
5 changed files with 403 additions and 247 deletions

View File

@ -2,6 +2,7 @@
<protocol name="ext_image_source_v1"> <protocol name="ext_image_source_v1">
<copyright> <copyright>
Copyright © 2022 Andri Yngvason Copyright © 2022 Andri Yngvason
Copyright © 2024 Simon Ser
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),
@ -30,18 +31,41 @@
This protocol may be extended to support more image sources in the future, This protocol may be extended to support more image sources in the future,
thereby adding those image sources to other protocols that use the image thereby adding those image sources to other protocols that use the image
source object without having to modify those protocols. source object without having to modify those protocols.
Warning! The protocol described in this file is currently in the testing
phase. Backward compatible changes may be added together with the
corresponding interface version bump. Backward incompatible changes can
only be done by creating a new major version of the extension.
</description> </description>
<interface name="ext_image_source_manager_v1" version="1"> <interface name="ext_image_source_v1" version="1">
<description summary="opaque image source manager"> <description summary="opaque image source object">
A manager for creating image source objects for standard objects. Sources The image source object is an opaque descriptor for a capturable resource.
may also be created from elsewhere. This resource may be any sort of entity from which an image may be
derived.
Note, because ext_image_source_v1 objects are created from multiple
independent factory interfaces, the ext_image_source_v1 interface is
frozen at version 1.
</description> </description>
<request name="create_output_source"> <request name="destroy" type="destructor">
<description summary="delete this object">
Destroys the image source. This request may be sent at any time by the
client.
</description>
</request>
</interface>
<interface name="ext_output_image_source_manager_v1" version="1">
<description summary="image source manager for outputs">
A manager for creating image source objects for wl_output objects.
</description>
<request name="create_source">
<description summary="create source object for output"> <description summary="create source object for output">
Creates a source object for an output. Images captured from this source Creates a source object for an output. Images captured from this source
will show the same image as the output. Some elements may be omitted, will show the same content as the output. Some elements may be omitted,
such as cursors and overlays that have been marked as transparent to such as cursors and overlays that have been marked as transparent to
capturing. capturing.
</description> </description>
@ -57,21 +81,4 @@
</description> </description>
</request> </request>
</interface> </interface>
<interface name="ext_image_source_v1" version="1">
<description summary="opaque image source object">
The image source object is an opaque descriptor for a capturable resource.
This resource may be any sort of entity from which an image may be
derived.
This interface may not be extended.
</description>
<request name="destroy" type="destructor">
<description summary="delete this object">
Destroys the image source. This request may be sent at any time by the
client.
</description>
</request>
</interface>
</protocol> </protocol>

View File

@ -1,7 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<protocol name="ext_screencopy_v1"> <protocol name="ext_screencopy_v1">
<copyright> <copyright>
Copyright © 2021-2022 Andri Yngvason Copyright © 2021-2023 Andri Yngvason
Copyright © 2024 Simon Ser
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),
@ -27,14 +28,10 @@
This protocol allows clients to ask the compositor to capture screen This protocol allows clients to ask the compositor to capture screen
contents to user submitted buffers. contents to user submitted buffers.
Warning! The protocol described in this file is experimental and Warning! The protocol described in this file is currently in the testing
backward incompatible changes may be made. Backward compatible changes phase. Backward compatible changes may be added together with the
may be added together with the corresponding interface version bump. corresponding interface version bump. Backward incompatible changes can
Backward incompatible changes are done by bumping the version number in only be done by creating a new major version of the extension.
the protocol and interface names and resetting the interface version.
Once the protocol is to be declared stable, the 'z' prefix and the
version number in the protocol and interface names are removed and the
interface version number is reset.
</description> </description>
<interface name="ext_screencopy_manager_v1" version="1"> <interface name="ext_screencopy_manager_v1" version="1">
@ -43,21 +40,20 @@
source. source.
</description> </description>
<enum name="error">
<entry name="invalid_option" value="1" summary="invalid option flag"/>
</enum>
<enum name="options" bitfield="true"> <enum name="options" bitfield="true">
<entry name="render_cursors" value="1"/> <entry name="paint_cursors" value="1" summary="paint cursors onto captured frames"/>
</enum> </enum>
<enum name="input_type"> <request name="create_session">
<entry name="pointer" value="1"/>
<entry name="touch" value="2"/>
</enum>
<request name="capture">
<description summary="capture an image source"> <description summary="capture an image source">
Create a capturing session for an image source. Create a capturing session for an image source.
If the "render_cursors" flag is set, cursors shall be composited onto If the paint_cursors option is set, cursors shall be composited onto
the captured frame. The cursor should not be composited onto the frame the captured frame. The cursor shall not be composited onto the frame
if this flag is not set. if this flag is not set.
</description> </description>
<arg name="session" type="new_id" interface="ext_screencopy_session_v1"/> <arg name="session" type="new_id" interface="ext_screencopy_session_v1"/>
@ -65,189 +61,248 @@
<arg name="options" type="uint" enum="options"/> <arg name="options" type="uint" enum="options"/>
</request> </request>
<request name="capture_cursor"> <request name="create_pointer_cursor_session">
<description summary="capture the cursor of an image source"> <description summary="capture the pointer cursor of an image source">
Create a cursor capturing session for an image source. Create a cursor capturing session for the pointer of an image source.
The options argument has no effect and should be set to 0. This is The options argument has no effect and must be set to 0. This is
intended for any future flags that might be added. intended for any future flags that might be added.
</description> </description>
<arg name="session" type="new_id" interface="ext_screencopy_cursor_session_v1"/> <arg name="session" type="new_id" interface="ext_screencopy_cursor_session_v1"/>
<arg name="source" type="object" interface="ext_image_source_v1"/> <arg name="source" type="object" interface="ext_image_source_v1"/>
<arg name="seat" type="object" interface="wl_seat"/> <arg name="pointer" type="object" interface="wl_pointer"/>
<arg name="input_type" type="uint" enum="input_type"/>
<arg name="options" type="uint"/> <arg name="options" type="uint"/>
</request> </request>
<request name="destroy" type="destructor">
<description summary="destroy the manager">
Destroy the manager object.
Other objects created via this interface are unaffected.
</description>
</request>
</interface> </interface>
<interface name="ext_screencopy_session_v1" version="1"> <interface name="ext_screencopy_session_v1" version="1">
<description summary="capturing session"> <description summary="screen capture session">
This is the frame capturing interface. It keeps track of changes between This object represents an active screencopy session.
frames.
After a screencopy session is created, buffer constraint events will be After a screencopy session is created, buffer constraint events will be
emitted from the compositor to tell the client which buffer types and emitted from the compositor to tell the client which buffer types and
formats are supported for reading from the session. formats are supported for reading from the session. The compositor may
re-send buffer constraint events whenever they change.
When the client knows all the buffer attributes, it can create a buffer, The advertise buffer constraints, the compositor must send in no
attach it to the screencopy session using the "attach_buffer" request, particular order: zero or more shm_format and dmabuf_format events, zero
set the buffer damage using the "damage_buffer" request and then call or one dmabuf_device event, and exactly one buffer_size event. Then the
the "commit" request. compositor must send a done event.
After copying, a series of events will be generated, ending with the When the client has received all the buffer constraints, it can create a
"ready" event, which means that the buffer is ready to be used and a buffer accordingly, attach it to the screencopy session using the
buffer may be committed to the session again. The buffer may be re-used attach_buffer request, set the buffer damage using the damage_buffer
after the "ready" event. The "wl_buffer.release" event is not used. request and then send the capture request.
The compositor should present frames to the client at a steady rate,
unless otherwise instructed (see "on_damage" option).
A client wishing to capture all frames without missing any of them, should
commit a new buffer immediately after receiving the "ready" event.
The "failed" event may be sent at any time. When this happens, the client
must destroy the session. Depending on the failure reason, the client can
create a new session to replace it.
</description> </description>
<enum name="failure_reason"> <event name="buffer_size">
<entry name="invalid_buffer" value="1"/>
<entry name="output_missing" value="2"/>
<entry name="output_disabled" value="3"/>
<entry name="unknown_input" value="4"/>
</enum>
<enum name="options" bitfield="true">
<entry name="on_damage" value="1"/>
</enum>
<event name="format_shm">
<description summary="shm buffer format">
Provides the format that must be used for shm buffers.
This may be emitted multiple times, in which case the client may choose
any given format.
</description>
<arg name="format" type="uint" enum="wl_shm.format" summary="shm format"/>
</event>
<event name="format_drm">
<description summary="dma buffer constraints">
Provides the format that must be used for dma buffers.
This may be emitted multiple times, in which case the client may choose
any given format.
</description>
<arg name="format" type="uint" summary="drm format"/>
</event>
<event name="dimensions">
<description summary="image source dimensions"> <description summary="image source dimensions">
Provides the dimensions of the source image in buffer pixel coordinates. Provides the dimensions of the source image in buffer pixel coordinates.
The client must submit buffers that are large enough for the source The client must attach buffers that match this size.
image.
</description> </description>
<arg name="width" type="uint" summary="buffer width"/> <arg name="width" type="uint" summary="buffer width"/>
<arg name="height" type="uint" summary="buffer height"/> <arg name="height" type="uint" summary="buffer height"/>
</event> </event>
<event name="constraints_done"> <event name="shm_format">
<description summary="session initialisation done"> <description summary="shm buffer format">
This event is sent once when all constraint events have been sent. Provides the format that must be used for shared-memory buffers.
This event may be emitted multiple times, in which case the client may
choose any given format.
</description>
<arg name="format" type="uint" enum="wl_shm.format" summary="shm format"/>
</event>
<event name="dmabuf_device">
<description summary="dma-buf device">
This event advertises the device buffers must be allocated on for
dma-buf buffers.
In general the device is a DRM node. The DRM node type (primary vs.
render) is unspecified. Clients must not rely on the compositor sending
a particular node type. Clients cannot check two devices for equality
by comparing the dev_t value.
</description>
<arg name="device" type="array" summary="device dev_t value"/>
</event>
<event name="dmabuf_format">
<description summary="dma-buf format">
Provides the format that must be used for dma-buf buffers.
The client may choose any of the modifiers advertised in the array of
64-bit unsigned integers.
This event may be emitted multiple times, in which case the client may
choose any given format.
</description>
<arg name="format" type="uint" summary="drm format code"/>
<arg name="modifiers" type="array" summary="drm format modifiers"/>
</event>
<event name="done">
<description summary="all constraints have been sent">
This event is sent once when all buffer constraint events have been
sent.
The compositor must always end a batch of buffer constraint events with
this event, regardless of whether it sends the initial constraints or
an update.
</description> </description>
</event> </event>
<request name="attach_buffer"> <event name="stopped">
<description summary="attach buffer to session"> <description summary="session is no longer available">
Attach a buffer to the session. This event indicates that the capture session has stopped and is no
longer available. This can happen in a number of cases, e.g. when the
underlying source is destroyed, if the user decides to end the screen
capture, or if an unrecoverable runtime error has occurred.
The buffer must satisfy the constraints given by the The client should destroy the session after receiving this event.
"buffer_constraints_shm" and "buffer_constraints_dmabuf" events.
If an over-sized buffer is committed, the compositor will place the
image into the top left corner of the buffer.
</description> </description>
<arg name="buffer" type="object" interface="wl_buffer"/> </event>
</request>
<request name="damage_buffer"> <request name="create_frame">
<description summary="damage buffer"> <description summary="create a frame">
Apply damage to the buffer which is to be committed next. Create a capture frame for this session.
This is for optimisation purposes. The compositor may use this
information to reduce copying.
The client must submit damage if it's using multiple buffers. Otherwise,
the server might not copy into damaged regions of the buffer.
These coordinates originate in the upper left corner of the buffer.
</description> </description>
<arg name="x" type="uint" summary="region x coordinates"/> <arg name="frame" type="new_id" interface="ext_screencopy_frame_v1"/>
<arg name="y" type="uint" summary="region y coordinates"/>
<arg name="width" type="uint" summary="region width"/>
<arg name="height" type="uint" summary="region height"/>
</request>
<request name="commit">
<description summary="commit session">
Commit the screencopy session.
The frame will be copied to the attached buffer on next output commit. A
ready event is generated when the buffer is ready.
If the "on_damage" flag is set, the compositor should skip sending new
frames to the client until there is damage.
</description>
<arg name="options" type="uint" enum="options"/>
</request> </request>
<request name="destroy" type="destructor"> <request name="destroy" type="destructor">
<description summary="delete this object"> <description summary="delete this object">
Destroys the session. This request can be sent at any time by the Destroys the session. This request can be sent at any time by the
client. client.
This request doesn't affect ext_screencopy_frame_v1 objects created by
this object.
</description>
</request>
</interface>
<interface name="ext_screencopy_frame_v1" version="1">
<description summary="screen capture frame">
This object represents a screen capture frame.
The client should attach a buffer, damage the buffer, and then send a
capture request.
If the screen capture is successful, the compositor will send the frame
metadata (transform, damage, presentation_time in any order) followed by
the ready event.
If the screen capture fails, the compositor will send the failed event.
</description>
<enum name="error">
<entry name="no_buffer" value="1" summary="capture sent without attach_buffer"/>
<entry name="invalid_buffer_damage" value="2" summary="invalid buffer damage"/>
<entry name="already_captured" value="3" summary="capture request has been sent"/>
</enum>
<request name="destroy" type="destructor">
<description summary="destroy this object">
Destroys the session. This request can be sent at any time by the
client.
</description>
</request>
<request name="attach_buffer">
<description summary="attach buffer to session">
Attach a buffer to the session.
The wl_buffer.release request is unused.
This request must not be sent after capture, or else the
already_captured protocol error is raised.
</description>
<arg name="buffer" type="object" interface="wl_buffer"/>
</request>
<request name="damage_buffer">
<description summary="damage buffer">
Apply damage to the buffer which is to be captured next. This request
may be sent multiple times to describe a region.
The client indicates the accumulated damage since this wl_buffer was
last captured. During capture, the compositor will update the buffer
with at least the union of the region passed by the client and the
region advertised by ext_screencopy_frame_v1.damage.
When a wl_buffer is captured for the first time, or when the client
doesn't track damage, the client must damage the whole buffer.
This is for optimisation purposes. The compositor may use this
information to reduce copying.
These coordinates originate from the upper left corner of the buffer.
If x or y are strictly negative, or if width or height are negative or
zero, the invalid_buffer_damage protocol error is raised.
This request must not be sent after capture, or else the
already_captured protocol error is raised.
</description>
<arg name="x" type="int" summary="region x coordinate"/>
<arg name="y" type="int" summary="region y coordinate"/>
<arg name="width" type="int" summary="region width"/>
<arg name="height" type="int" summary="region height"/>
</request>
<request name="capture">
<description summary="capture a frame">
Capture a frame.
Unless this is the first successful captured frame performed in this
session, the compositor may wait an indefinite amount of time for the
source content to change before performing the copy.
This request may only be sent once, or else the already_captured
protocol error is raised. A buffer must be attached before this request
is sent, or else the no_buffer protocol error is raised.
</description> </description>
</request> </request>
<event name="transform"> <event name="transform">
<description summary="carries the output transform"> <description summary="buffer transform">
This event is sent before the ready event and holds the output transform This event is sent before the ready event and holds the transform of
of the source buffer. the source buffer.
</description> </description>
<arg name="transform" type="int" enum="wl_output.transform"/> <arg name="transform" type="uint" enum="wl_output.transform"/>
</event> </event>
<event name="damage"> <event name="damage">
<description summary="carries the coordinates of the damaged region"> <description summary="buffer damaged region">
This event is sent before the ready event. It may be generated multiple This event is sent before the ready event. It may be generated multiple
times for each commit. times to describe a region.
A capture session's initial damage encompasses the whole captured area. The first captured frame in a session will always carry full damage.
Subsequent frames' damaged regions describe which parts of the buffer
The arguments describe a box around an area that has changed since the have changed since the last ready event.
last ready event.
These coordinates originate in the upper left corner of the buffer. These coordinates originate in the upper left corner of the buffer.
</description> </description>
<arg name="x" type="uint" summary="damaged x coordinates"/> <arg name="x" type="int" summary="damage x coordinate"/>
<arg name="y" type="uint" summary="damaged y coordinates"/> <arg name="y" type="int" summary="damage y coordinate"/>
<arg name="width" type="uint" summary="current width"/> <arg name="width" type="int" summary="damage width"/>
<arg name="height" type="uint" summary="current height"/> <arg name="height" type="int" summary="damage height"/>
</event>
<event name="failed">
<description summary="commit failed">
This event indicates that the attempted frame copy has failed.
After receiving this event, the client must destroy the object.
</description>
<arg name="reason" type="uint" enum="failure_reason"/>
</event> </event>
<event name="presentation_time"> <event name="presentation_time">
<description summary="indicates the presentation time of the frame"> <description summary="presentation time of the frame">
This event indicates the time at which the frame is presented to the This event indicates the time at which the frame is presented to the
output in system monotonic time. output in system monotonic time. This event is sent before the ready
event.
The timestamp is expressed as tv_sec_hi, tv_sec_lo, tv_nsec triples, The timestamp is expressed as tv_sec_hi, tv_sec_lo, tv_nsec triples,
each component being an unsigned 32-bit value. Whole seconds are in each component being an unsigned 32-bit value. Whole seconds are in
@ -264,35 +319,95 @@
</event> </event>
<event name="ready"> <event name="ready">
<description summary="indicates frame is available for reading"> <description summary="frame is available for reading">
Called as soon as the frame is copied, indicating it is available Called as soon as the frame is copied, indicating it is available
for reading. for reading.
The buffer may be re-used by the client after the "ready" event. The buffer may be re-used by the client after this event.
After receiving this event, the client must destroy the object.
</description> </description>
</event> </event>
<enum name="failure_reason">
<entry name="unknown" value="0">
<description summary="unknown runtime error">
An unspecified runtime error has occurred. The client may retry.
</description>
</entry>
<entry name="buffer_constraints" value="1">
<description summary="buffer constraints mismatch">
The buffer submitted by the client doesn't match the latest session
constraints. The client should re-allocate its buffers and retry.
</description>
</entry>
<entry name="stopped" value="2">
<description summary="session is no longer available">
The session has stopped. See ext_screencopy_session_v1.stopped.
</description>
</entry>
</enum>
<event name="failed">
<description summary="capture failed">
This event indicates that the attempted frame copy has failed.
After receiving this event, the client must destroy the object.
</description>
<arg name="reason" type="uint" enum="failure_reason"/>
</event>
</interface> </interface>
<interface name="ext_screencopy_cursor_session_v1" version="1"> <interface name="ext_screencopy_cursor_session_v1" version="1">
<description summary="cursor capture session">
This object represents a cursor capture session. It extends the base
capture session with cursor-specific metadata.
</description>
<enum name="error">
<entry name="duplicate_session" value="1" summary="get_screencopy_session sent twice"/>
</enum>
<request name="destroy" type="destructor">
<description summary="delete this object">
Destroys the session. This request can be sent at any time by the
client.
This request doesn't affect ext_screencopy_frame_v1 objects created by
this object.
</description>
</request>
<request name="get_screencopy_session"> <request name="get_screencopy_session">
<description summary="get screencopy session"> <description summary="get screencopy session">
Gets the screencopy session for this cursor session. Gets the screencopy session for this cursor session.
The session will produce frames of the cursor image. The compositor may
pause the session when the cursor leaves the captured area.
This request must not be sent more than once, or else the
duplicate_session protocol error is raised.
</description> </description>
<arg name="session" type="new_id" interface="ext_screencopy_session_v1"/> <arg name="session" type="new_id" interface="ext_screencopy_session_v1"/>
</request> </request>
<event name="enter"> <event name="enter">
<description summary="cursor entered captured are"> <description summary="cursor entered captured area">
Sent when a cursor enters the captured area. It shall be generated Sent when a cursor enters the captured area. It shall be generated
before the "position" and "hotspot" events when and only when a cursor before the "position" and "hotspot" events when and only when a cursor
enters the area. enters the area.
The cursor enters the captured area when the cursor image intersects
with the captured area. Note, this is different from e.g.
wl_pointer.enter.
</description> </description>
</event> </event>
<event name="leave"> <event name="leave">
<description summary="cursor left area"> <description summary="cursor left captured area">
Sent when a cursor leaves the captured area. No "position" or "hotspot" Sent when a cursor leaves the captured area. No "position" or "hotspot"
event is generated for the cursor. event is generated for the cursor until the cursor enters the captured
area again.
</description> </description>
</event> </event>
@ -305,8 +420,9 @@
relative to the main buffer's top left corner in transformed buffer relative to the main buffer's top left corner in transformed buffer
pixel coordinates. pixel coordinates.
The hotspot coordinates are relative to the cursor buffers upper left The position coordinates are relative to the main buffer's upper left
corner. corner. The coordinates may be negative or greater than the main buffer
size.
</description> </description>
<arg name="x" type="int" summary="position x coordinates"/> <arg name="x" type="int" summary="position x coordinates"/>
<arg name="y" type="int" summary="position y coordinates"/> <arg name="y" type="int" summary="position y coordinates"/>
@ -314,8 +430,14 @@
<event name="hotspot"> <event name="hotspot">
<description summary="hotspot changed"> <description summary="hotspot changed">
The hotspot describes the offset between the cursor image and the
position of the input device.
The given coordinates are the hotspot's offset from the origin in The given coordinates are the hotspot's offset from the origin in
buffer coordinates. buffer coordinates.
Clients should not apply the hotspot immediately: the hotspot becomes
effective when the next ext_screencopy_frame_v1.ready event is received.
</description> </description>
<arg name="x" type="int" summary="hotspot x coordinates"/> <arg name="x" type="int" summary="hotspot x coordinates"/>
<arg name="y" type="int" summary="hotspot y coordinates"/> <arg name="y" type="int" summary="hotspot y coordinates"/>

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2022 - 2023 Andri Yngvason * Copyright (c) 2022 - 2024 Andri Yngvason
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -36,13 +36,14 @@
#include "config.h" #include "config.h"
#include "logging.h" #include "logging.h"
extern struct ext_image_source_manager_v1* ext_image_source_manager; extern struct ext_output_image_source_manager_v1* ext_output_image_source_manager;
extern struct ext_screencopy_manager_v1* ext_screencopy_manager; extern struct ext_screencopy_manager_v1* ext_screencopy_manager;
struct ext_screencopy { struct ext_screencopy {
struct screencopy parent; struct screencopy parent;
struct wl_output* wl_output; struct wl_output* wl_output;
struct ext_screencopy_session_v1* session; struct ext_screencopy_session_v1* session;
struct ext_screencopy_frame_v1* frame;
struct ext_screencopy_cursor_session_v1* cursor; struct ext_screencopy_cursor_session_v1* cursor;
bool render_cursors; bool render_cursors;
struct wv_buffer_pool* pool; struct wv_buffer_pool* pool;
@ -63,40 +64,32 @@ struct ext_screencopy {
struct screencopy_impl ext_screencopy_impl; struct screencopy_impl ext_screencopy_impl;
static struct ext_screencopy_session_v1_listener session_listener; static struct ext_screencopy_session_v1_listener session_listener;
static struct ext_screencopy_cursor_session_v1_listener cursor_listener; static struct ext_screencopy_frame_v1_listener frame_listener;
//static struct ext_screencopy_cursor_session_v1_listener cursor_listener;
static int ext_screencopy_init_session(struct ext_screencopy* self) static int ext_screencopy_init_session(struct ext_screencopy* self)
{ {
if (self->frame)
ext_screencopy_frame_v1_destroy(self->frame);
self->frame = NULL;
if (self->session) if (self->session)
ext_screencopy_session_v1_destroy(self->session); ext_screencopy_session_v1_destroy(self->session);
self->session = NULL;
struct ext_image_source_v1* source; struct ext_image_source_v1* source;
source = ext_image_source_manager_v1_create_output_source( source = ext_output_image_source_manager_v1_create_source(
ext_image_source_manager, self->wl_output); ext_output_image_source_manager, self->wl_output);
if (!source) if (!source)
return -1; return -1;
enum ext_screencopy_manager_v1_options options = 0; enum ext_screencopy_manager_v1_options options = 0;
if (self->render_cursors) if (self->render_cursors)
options |= EXT_SCREENCOPY_MANAGER_V1_OPTIONS_RENDER_CURSORS; options |= EXT_SCREENCOPY_MANAGER_V1_OPTIONS_PAINT_CURSORS;
if (self->capture_cursor) { self->session = ext_screencopy_manager_v1_create_session(
self->cursor = ext_screencopy_manager_v1_capture_cursor( ext_screencopy_manager, source, options);
ext_screencopy_manager, source, NULL, ext_image_source_v1_destroy(source);
EXT_SCREENCOPY_MANAGER_V1_INPUT_TYPE_POINTER,
options);
ext_image_source_v1_destroy(source);
if (!self->cursor)
return -1;
self->session =
ext_screencopy_cursor_session_v1_get_screencopy_session(
self->cursor);
} else {
self->session = ext_screencopy_manager_v1_capture(
ext_screencopy_manager, source, options);
ext_image_source_v1_destroy(source);
}
if (!self->session) if (!self->session)
return -1; return -1;
@ -104,8 +97,7 @@ static int ext_screencopy_init_session(struct ext_screencopy* self)
&session_listener, self); &session_listener, self);
if (self->capture_cursor) { if (self->capture_cursor) {
ext_screencopy_cursor_session_v1_add_listener(self->cursor, // TODO: create_pointer_cursor_session
&cursor_listener, self);
} }
return 0; return 0;
@ -115,12 +107,21 @@ static int ext_screencopy_init_session(struct ext_screencopy* self)
static void ext_screencopy_schedule_capture(struct ext_screencopy* self, static void ext_screencopy_schedule_capture(struct ext_screencopy* self,
bool immediate) bool immediate)
{ {
assert(!self->frame);
// TODO: Restart session on immediate capture
self->buffer = wv_buffer_pool_acquire(self->pool); self->buffer = wv_buffer_pool_acquire(self->pool);
self->buffer->domain = self->capture_cursor ? WV_BUFFER_DOMAIN_CURSOR : self->buffer->domain = self->capture_cursor ? WV_BUFFER_DOMAIN_CURSOR :
WV_BUFFER_DOMAIN_OUTPUT; WV_BUFFER_DOMAIN_OUTPUT;
ext_screencopy_session_v1_attach_buffer(self->session, self->frame = ext_screencopy_session_v1_create_frame(self->session);
assert(self->frame);
ext_screencopy_frame_v1_attach_buffer(self->frame,
self->buffer->wl_buffer); self->buffer->wl_buffer);
ext_screencopy_frame_v1_add_listener(self->frame, &frame_listener,
self);
int n_rects = 0; int n_rects = 0;
struct pixman_box16* rects = struct pixman_box16* rects =
@ -132,16 +133,11 @@ static void ext_screencopy_schedule_capture(struct ext_screencopy* self,
uint32_t width = rects[i].x2 - x; uint32_t width = rects[i].x2 - x;
uint32_t height = rects[i].y2 - y; uint32_t height = rects[i].y2 - y;
ext_screencopy_session_v1_damage_buffer(self->session, x, y, ext_screencopy_frame_v1_damage_buffer(self->frame, x, y,
width, height); width, height);
} }
uint32_t flags = 0; ext_screencopy_frame_v1_capture(self->frame);
if (!immediate)
flags |= EXT_SCREENCOPY_SESSION_V1_OPTIONS_ON_DAMAGE;
ext_screencopy_session_v1_commit(self->session, flags);
nvnc_log(NVNC_LOG_DEBUG, "Committed buffer%s: %p\n", immediate ? " immediately" : "", nvnc_log(NVNC_LOG_DEBUG, "Committed buffer%s: %p\n", immediate ? " immediately" : "",
self->buffer); self->buffer);
@ -159,16 +155,24 @@ static void session_handle_format_shm(void *data,
static void session_handle_format_drm(void *data, static void session_handle_format_drm(void *data,
struct ext_screencopy_session_v1 *session, struct ext_screencopy_session_v1 *session,
uint32_t format) uint32_t format, struct wl_array* modifiers)
{ {
struct ext_screencopy* self = data; struct ext_screencopy* self = data;
#ifdef ENABLE_SCREENCOPY_DMABUF #ifdef ENABLE_SCREENCOPY_DMABUF
self->have_linux_dmabuf = true; self->have_linux_dmabuf = true;
self->dmabuf_format = format; self->dmabuf_format = format;
// TODO: Pass modifiers
#endif #endif
} }
static void session_handle_dmabuf_device(void* data,
struct ext_screencopy_session_v1* session,
struct wl_array *device)
{
// TODO
}
static void session_handle_dimensions(void *data, static void session_handle_dimensions(void *data,
struct ext_screencopy_session_v1 *session, uint32_t width, struct ext_screencopy_session_v1 *session, uint32_t width,
uint32_t height) uint32_t height)
@ -217,9 +221,14 @@ static void session_handle_constraints_done(void *data,
nvnc_log(NVNC_LOG_DEBUG, "Init done\n"); nvnc_log(NVNC_LOG_DEBUG, "Init done\n");
} }
static void session_handle_transform(void *data, static void session_handle_stopped(void* data,
struct ext_screencopy_session_v1 *session, struct ext_screencopy_session_v1* session)
int32_t transform) {
// TODO
}
static void frame_handle_transform(void *data,
struct ext_screencopy_frame_v1 *frame, uint32_t transform)
{ {
struct ext_screencopy* self = data; struct ext_screencopy* self = data;
@ -229,11 +238,15 @@ static void session_handle_transform(void *data,
nvnc_fb_set_transform(self->buffer->nvnc_fb, transform); nvnc_fb_set_transform(self->buffer->nvnc_fb, transform);
} }
static void session_handle_ready(void *data, static void frame_handle_ready(void *data,
struct ext_screencopy_session_v1 *session) struct ext_screencopy_frame_v1 *frame)
{ {
struct ext_screencopy* self = data; struct ext_screencopy* self = data;
assert(frame == self->frame);
ext_screencopy_frame_v1_destroy(self->frame);
self->frame = NULL;
nvnc_log(NVNC_LOG_DEBUG, "Ready!\n"); nvnc_log(NVNC_LOG_DEBUG, "Ready!\n");
assert(self->buffer); assert(self->buffer);
@ -249,12 +262,16 @@ static void session_handle_ready(void *data,
self->parent.on_done(SCREENCOPY_DONE, buffer, self->parent.userdata); self->parent.on_done(SCREENCOPY_DONE, buffer, self->parent.userdata);
} }
static void session_handle_failed(void *data, static void frame_handle_failed(void *data,
struct ext_screencopy_session_v1 *session, struct ext_screencopy_frame_v1 *frame,
enum ext_screencopy_session_v1_failure_reason reason) enum ext_screencopy_frame_v1_failure_reason reason)
{ {
struct ext_screencopy* self = data; struct ext_screencopy* self = data;
assert(frame == self->frame);
ext_screencopy_frame_v1_destroy(self->frame);
self->frame = NULL;
nvnc_log(NVNC_LOG_DEBUG, "Failed!\n"); nvnc_log(NVNC_LOG_DEBUG, "Failed!\n");
assert(self->buffer); assert(self->buffer);
@ -262,39 +279,44 @@ static void session_handle_failed(void *data,
wv_buffer_pool_release(self->pool, self->buffer); wv_buffer_pool_release(self->pool, self->buffer);
self->buffer = NULL; self->buffer = NULL;
if (reason == EXT_SCREENCOPY_SESSION_V1_FAILURE_REASON_INVALID_BUFFER) { if (reason == EXT_SCREENCOPY_FRAME_V1_FAILURE_REASON_BUFFER_CONSTRAINTS) {
ext_screencopy_init_session(self); ext_screencopy_init_session(self);
} }
self->parent.on_done(SCREENCOPY_FAILED, NULL, self->parent.userdata); self->parent.on_done(SCREENCOPY_FAILED, NULL, self->parent.userdata);
} }
static void session_handle_damage(void *data, static void frame_handle_damage(void *data,
struct ext_screencopy_session_v1 *session, struct ext_screencopy_frame_v1 *frame,
uint32_t x, uint32_t y, uint32_t width, uint32_t height) int32_t x, int32_t y, int32_t width, int32_t height)
{ {
struct ext_screencopy* self = data; struct ext_screencopy* self = data;
wv_buffer_damage_rect(self->buffer, x, y, width, height); wv_buffer_damage_rect(self->buffer, x, y, width, height);
} }
static void session_handle_presentation_time(void *data, static void frame_handle_presentation_time(void *data,
struct ext_screencopy_session_v1 *session, struct ext_screencopy_frame_v1 *frame,
uint32_t sec_hi, uint32_t sec_lo, uint32_t nsec) uint32_t sec_hi, uint32_t sec_lo, uint32_t nsec)
{ {
// TODO // TODO
} }
static struct ext_screencopy_session_v1_listener session_listener = { static struct ext_screencopy_session_v1_listener session_listener = {
.format_shm = session_handle_format_shm, .shm_format = session_handle_format_shm,
.format_drm = session_handle_format_drm, .dmabuf_format = session_handle_format_drm,
.dimensions = session_handle_dimensions, .dmabuf_device = session_handle_dmabuf_device,
.constraints_done = session_handle_constraints_done, .buffer_size = session_handle_dimensions,
.damage = session_handle_damage, .done = session_handle_constraints_done,
.presentation_time = session_handle_presentation_time, .stopped = session_handle_stopped,
.transform = session_handle_transform, };
.ready = session_handle_ready,
.failed = session_handle_failed, static struct ext_screencopy_frame_v1_listener frame_listener = {
.damage = frame_handle_damage,
.presentation_time = frame_handle_presentation_time,
.transform = frame_handle_transform,
.ready = frame_handle_ready,
.failed = frame_handle_failed,
}; };
static void cursor_handle_enter(void* data, static void cursor_handle_enter(void* data,
@ -327,12 +349,14 @@ static void cursor_handle_hotspot(void* data,
self->parent.cursor_hotspot(x, y, self->parent.userdata); self->parent.cursor_hotspot(x, y, self->parent.userdata);
} }
/*
static struct ext_screencopy_cursor_session_v1_listener cursor_listener = { static struct ext_screencopy_cursor_session_v1_listener cursor_listener = {
.enter = cursor_handle_enter, .enter = cursor_handle_enter,
.leave = cursor_handle_leave, .leave = cursor_handle_leave,
.position = cursor_handle_position, .position = cursor_handle_position,
.hotspot = cursor_handle_hotspot, .hotspot = cursor_handle_hotspot,
}; };
*/
static int ext_screencopy_start(struct screencopy* ptr, bool immediate) static int ext_screencopy_start(struct screencopy* ptr, bool immediate)
{ {
@ -414,6 +438,8 @@ void ext_screencopy_destroy(struct screencopy* ptr)
{ {
struct ext_screencopy* self = (struct ext_screencopy*)ptr; struct ext_screencopy* self = (struct ext_screencopy*)ptr;
if (self->frame)
ext_screencopy_frame_v1_destroy(self->frame);
if (self->session) if (self->session)
ext_screencopy_session_v1_destroy(self->session); ext_screencopy_session_v1_destroy(self->session);
if (self->buffer) if (self->buffer)

View File

@ -172,7 +172,7 @@ struct gbm_device* gbm_device = NULL;
struct zxdg_output_manager_v1* xdg_output_manager = NULL; struct zxdg_output_manager_v1* xdg_output_manager = NULL;
struct zwlr_output_power_manager_v1* wlr_output_power_manager = NULL; struct zwlr_output_power_manager_v1* wlr_output_power_manager = NULL;
struct zwlr_screencopy_manager_v1* screencopy_manager = NULL; struct zwlr_screencopy_manager_v1* screencopy_manager = NULL;
struct ext_image_source_manager_v1* ext_image_source_manager = NULL; struct ext_output_image_source_manager_v1* ext_output_image_source_manager = NULL;
struct ext_screencopy_manager_v1* ext_screencopy_manager = NULL; struct ext_screencopy_manager_v1* ext_screencopy_manager = NULL;
extern struct screencopy_impl wlr_screencopy_impl, ext_screencopy_impl; extern struct screencopy_impl wlr_screencopy_impl, ext_screencopy_impl;
@ -303,10 +303,11 @@ static void registry_add(void* data, struct wl_registry* registry,
return; return;
} }
if (strcmp(interface, ext_image_source_manager_v1_interface.name) == 0) { if (strcmp(interface, ext_output_image_source_manager_v1_interface.name) == 0) {
ext_image_source_manager = wl_registry_bind(registry, id, ext_output_image_source_manager =
&ext_image_source_manager_v1_interface, wl_registry_bind(registry, id,
MIN(1, version)); &ext_output_image_source_manager_v1_interface,
MIN(1, version));
return; return;
} }
#endif #endif
@ -496,9 +497,9 @@ static void wayland_detach(struct wayvnc* self)
zwlr_screencopy_manager_v1_destroy(screencopy_manager); zwlr_screencopy_manager_v1_destroy(screencopy_manager);
screencopy_manager = NULL; screencopy_manager = NULL;
if (ext_image_source_manager) if (ext_output_image_source_manager)
ext_image_source_manager_v1_destroy(ext_image_source_manager); ext_output_image_source_manager_v1_destroy(ext_output_image_source_manager);
ext_image_source_manager = NULL; ext_output_image_source_manager = NULL;
if (ext_screencopy_manager) if (ext_screencopy_manager)
ext_screencopy_manager_v1_destroy(ext_screencopy_manager); ext_screencopy_manager_v1_destroy(ext_screencopy_manager);
@ -609,9 +610,6 @@ static int init_wayland(struct wayvnc* self, const char* display)
goto failure; goto failure;
} }
self->screencopy->on_done = on_capture_done;
self->screencopy->userdata = self;
self->wl_handler = aml_handler_new(wl_display_get_fd(self->display), self->wl_handler = aml_handler_new(wl_display_get_fd(self->display),
on_wayland_event, self, NULL); on_wayland_event, self, NULL);
if (!self->wl_handler) if (!self->wl_handler)
@ -953,7 +951,7 @@ static int init_nvnc(struct wayvnc* self, const char* addr, uint16_t port,
nvnc_set_name(self->nvnc, "WayVNC"); nvnc_set_name(self->nvnc, "WayVNC");
nvnc_set_desktop_layout_fn(self->nvnc, on_client_resize); //nvnc_set_desktop_layout_fn(self->nvnc, on_client_resize);
enum nvnc_auth_flags auth_flags = 0; enum nvnc_auth_flags auth_flags = 0;
if (self->cfg.enable_auth) { if (self->cfg.enable_auth) {
@ -1567,6 +1565,9 @@ bool configure_screencopy(struct wayvnc* self)
return false; return false;
} }
self->screencopy->on_done = on_capture_done;
self->screencopy->userdata = self;
self->screencopy->rate_limit = self->max_rate; self->screencopy->rate_limit = self->max_rate;
self->screencopy->enable_linux_dmabuf = self->enable_gpu_features; self->screencopy->enable_linux_dmabuf = self->enable_gpu_features;

View File

@ -19,7 +19,7 @@
#include <unistd.h> #include <unistd.h>
extern struct zwlr_screencopy_manager_v1* screencopy_manager; extern struct zwlr_screencopy_manager_v1* screencopy_manager;
extern struct ext_image_source_manager_v1* ext_image_source_manager; extern struct ext_output_image_source_manager_v1* ext_output_image_source_manager;
extern struct ext_screencopy_manager_v1* ext_screencopy_manager; extern struct ext_screencopy_manager_v1* ext_screencopy_manager;
extern struct screencopy_impl wlr_screencopy_impl; extern struct screencopy_impl wlr_screencopy_impl;
@ -28,7 +28,7 @@ extern struct screencopy_impl ext_screencopy_impl;
struct screencopy* screencopy_create(struct wl_output* output, struct screencopy* screencopy_create(struct wl_output* output,
bool render_cursor) bool render_cursor)
{ {
if (ext_screencopy_manager && ext_image_source_manager) if (ext_screencopy_manager && ext_output_image_source_manager)
return ext_screencopy_impl.create(output, render_cursor); return ext_screencopy_impl.create(output, render_cursor);
if (screencopy_manager) if (screencopy_manager)
return wlr_screencopy_impl.create(output, render_cursor); return wlr_screencopy_impl.create(output, render_cursor);