wlr_export_dmabuf_v1.c 7.28 KB
Newer Older
1 2 3
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
4
#include <wlr/interfaces/wlr_output.h>
emersion's avatar
emersion committed
5
#include <wlr/render/dmabuf.h>
6 7
#include <wlr/types/wlr_export_dmabuf_v1.h>
#include <wlr/types/wlr_output.h>
8
#include <wlr/util/log.h>
9 10
#include "util/signal.h"
#include "wlr-export-dmabuf-unstable-v1-protocol.h"
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32

#define EXPORT_DMABUF_MANAGER_VERSION 1


static const struct zwlr_export_dmabuf_frame_v1_interface frame_impl;

static struct wlr_export_dmabuf_frame_v1 *frame_from_resource(
		struct wl_resource *resource) {
	assert(wl_resource_instance_of(resource,
		&zwlr_export_dmabuf_frame_v1_interface, &frame_impl));
	return wl_resource_get_user_data(resource);
}

static void frame_handle_destroy(struct wl_client *client,
		struct wl_resource *resource) {
	wl_resource_destroy(resource);
}

static const struct zwlr_export_dmabuf_frame_v1_interface frame_impl = {
	.destroy = frame_handle_destroy,
};

33 34 35 36 37 38 39
static void frame_destroy(struct wlr_export_dmabuf_frame_v1 *frame) {
	if (frame == NULL) {
		return;
	}
	if (frame->cursor_locked) {
		wlr_output_lock_software_cursors(frame->output, false);
	}
40
	wl_list_remove(&frame->link);
41
	wl_list_remove(&frame->output_precommit.link);
42
	wlr_dmabuf_attributes_finish(&frame->attribs);
43 44
	// Make the frame resource inert
	wl_resource_set_user_data(frame->resource, NULL);
45 46 47
	free(frame);
}

48 49 50 51 52
static void frame_handle_resource_destroy(struct wl_resource *resource) {
	struct wlr_export_dmabuf_frame_v1 *frame = frame_from_resource(resource);
	frame_destroy(frame);
}

53
static void frame_output_handle_precommit(struct wl_listener *listener,
54 55
		void *data) {
	struct wlr_export_dmabuf_frame_v1 *frame =
56 57
		wl_container_of(listener, frame, output_precommit);
	struct wlr_output_event_precommit *event = data;
58

59 60 61 62 63 64
	if (!(event->output->pending.committed & WLR_OUTPUT_STATE_BUFFER)) {
		return;
	}

	wl_list_remove(&frame->output_precommit.link);
	wl_list_init(&frame->output_precommit.link);
65

66 67 68
	time_t tv_sec = event->when->tv_sec;
	uint32_t tv_sec_hi = (sizeof(tv_sec) > 4) ? tv_sec >> 32 : 0;
	uint32_t tv_sec_lo = tv_sec & 0xFFFFFFFF;
69 70
	zwlr_export_dmabuf_frame_v1_send_ready(frame->resource,
		tv_sec_hi, tv_sec_lo, event->when->tv_nsec);
71
	frame_destroy(frame);
72 73
}

74 75 76 77 78 79 80 81 82 83 84 85

static const struct zwlr_export_dmabuf_manager_v1_interface manager_impl;

static struct wlr_export_dmabuf_manager_v1 *manager_from_resource(
		struct wl_resource *resource) {
	assert(wl_resource_instance_of(resource,
		&zwlr_export_dmabuf_manager_v1_interface, &manager_impl));
	return wl_resource_get_user_data(resource);
}

static void manager_handle_capture_output(struct wl_client *client,
		struct wl_resource *manager_resource, uint32_t id,
emersion's avatar
emersion committed
86
		int32_t overlay_cursor, struct wl_resource *output_resource) {
87 88 89 90 91 92 93 94 95 96 97 98
	struct wlr_export_dmabuf_manager_v1 *manager =
		manager_from_resource(manager_resource);
	struct wlr_output *output = wlr_output_from_resource(output_resource);

	struct wlr_export_dmabuf_frame_v1 *frame =
		calloc(1, sizeof(struct wlr_export_dmabuf_frame_v1));
	if (frame == NULL) {
		wl_resource_post_no_memory(manager_resource);
		return;
	}
	frame->manager = manager;
	frame->output = output;
99
	wl_list_init(&frame->output_precommit.link);
100 101 102 103 104 105

	uint32_t version = wl_resource_get_version(manager_resource);
	frame->resource = wl_resource_create(client,
		&zwlr_export_dmabuf_frame_v1_interface, version, id);
	if (frame->resource == NULL) {
		wl_client_post_no_memory(client);
106
		free(frame);
107 108 109 110 111 112 113
		return;
	}
	wl_resource_set_implementation(frame->resource, &frame_impl, frame,
		frame_handle_resource_destroy);

	wl_list_insert(&manager->frames, &frame->link);

114 115
	if (!output->impl->export_dmabuf) {
		zwlr_export_dmabuf_frame_v1_send_cancel(frame->resource,
emersion's avatar
emersion committed
116
			ZWLR_EXPORT_DMABUF_FRAME_V1_CANCEL_REASON_PERMANENT);
117
		frame_destroy(frame);
118 119 120
		return;
	}

121
	struct wlr_dmabuf_attributes *attribs = &frame->attribs;
122
	if (!wlr_output_export_dmabuf(output, attribs)) {
emersion's avatar
emersion committed
123 124
		zwlr_export_dmabuf_frame_v1_send_cancel(frame->resource,
			ZWLR_EXPORT_DMABUF_FRAME_V1_CANCEL_REASON_TEMPORARY);
125
		frame_destroy(frame);
126 127 128
		return;
	}

129 130 131 132 133
	if (overlay_cursor) {
		wlr_output_lock_software_cursors(frame->output, true);
		frame->cursor_locked = true;
	}

emersion's avatar
emersion committed
134
	uint32_t frame_flags = ZWLR_EXPORT_DMABUF_FRAME_V1_FLAGS_TRANSIENT;
135 136
	uint32_t mod_high = attribs->modifier >> 32;
	uint32_t mod_low = attribs->modifier & 0xFFFFFFFF;
137 138

	zwlr_export_dmabuf_frame_v1_send_frame(frame->resource,
emersion's avatar
emersion committed
139
		output->width, output->height, 0, 0, attribs->flags, frame_flags,
emersion's avatar
emersion committed
140
		attribs->format, mod_high, mod_low, attribs->n_planes);
141

142 143
	for (int i = 0; i < attribs->n_planes; ++i) {
		off_t size = lseek(attribs->fd[i], 0, SEEK_END);
144

emersion's avatar
emersion committed
145
		zwlr_export_dmabuf_frame_v1_send_object(frame->resource, i,
emersion's avatar
emersion committed
146
			attribs->fd[i], size, attribs->offset[i], attribs->stride[i], i);
147 148
	}

149 150 151
	wl_list_remove(&frame->output_precommit.link);
	wl_signal_add(&output->events.precommit, &frame->output_precommit);
	frame->output_precommit.notify = frame_output_handle_precommit;
152 153
}

154 155 156 157 158
static void manager_handle_destroy(struct wl_client *client,
		struct wl_resource *manager_resource) {
	wl_resource_destroy(manager_resource);
}

159 160
static const struct zwlr_export_dmabuf_manager_v1_interface manager_impl = {
	.capture_output = manager_handle_capture_output,
161
	.destroy = manager_handle_destroy,
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
};

static void manager_handle_resource_destroy(struct wl_resource *resource) {
	wl_list_remove(wl_resource_get_link(resource));
}

static void manager_bind(struct wl_client *client, void *data, uint32_t version,
		uint32_t id) {
	struct wlr_export_dmabuf_manager_v1 *manager = data;

	struct wl_resource *resource = wl_resource_create(client,
		&zwlr_export_dmabuf_manager_v1_interface, version, id);
	if (resource == NULL) {
		wl_client_post_no_memory(client);
		return;
	}
	wl_resource_set_implementation(resource, &manager_impl, manager,
		manager_handle_resource_destroy);

	wl_list_insert(&manager->resources, wl_resource_get_link(resource));
}

static void handle_display_destroy(struct wl_listener *listener, void *data) {
	struct wlr_export_dmabuf_manager_v1 *manager =
		wl_container_of(listener, manager, display_destroy);
	wlr_export_dmabuf_manager_v1_destroy(manager);
}

struct wlr_export_dmabuf_manager_v1 *wlr_export_dmabuf_manager_v1_create(
		struct wl_display *display) {
	struct wlr_export_dmabuf_manager_v1 *manager =
		calloc(1, sizeof(struct wlr_export_dmabuf_manager_v1));
	if (manager == NULL) {
		return NULL;
	}
	wl_list_init(&manager->resources);
	wl_list_init(&manager->frames);
199
	wl_signal_init(&manager->events.destroy);
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219

	manager->global = wl_global_create(display,
		&zwlr_export_dmabuf_manager_v1_interface, EXPORT_DMABUF_MANAGER_VERSION,
		manager, manager_bind);
	if (manager->global == NULL) {
		free(manager);
		return NULL;
	}

	manager->display_destroy.notify = handle_display_destroy;
	wl_display_add_destroy_listener(display, &manager->display_destroy);

	return manager;
}

void wlr_export_dmabuf_manager_v1_destroy(
		struct wlr_export_dmabuf_manager_v1 *manager) {
	if (manager == NULL) {
		return;
	}
220
	wlr_signal_emit_safe(&manager->events.destroy, manager);
221 222 223 224 225 226 227 228 229 230 231 232
	wl_list_remove(&manager->display_destroy.link);
	wl_global_destroy(manager->global);
	struct wl_resource *resource, *resource_tmp;
	wl_resource_for_each_safe(resource, resource_tmp, &manager->resources) {
		wl_resource_destroy(resource);
	}
	struct wlr_export_dmabuf_frame_v1 *frame, *frame_tmp;
	wl_list_for_each_safe(frame, frame_tmp, &manager->frames, link) {
		wl_resource_destroy(frame->resource);
	}
	free(manager);
}