summaryrefslogtreecommitdiff
path: root/capture_wlr.c
diff options
context:
space:
mode:
Diffstat (limited to 'capture_wlr.c')
-rw-r--r--capture_wlr.c329
1 files changed, 0 insertions, 329 deletions
diff --git a/capture_wlr.c b/capture_wlr.c
deleted file mode 100644
index 0e5b56d..0000000
--- a/capture_wlr.c
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * Copyright (C) 2023 Mikhail Burakov. This file is part of streamer.
- *
- * streamer is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * streamer is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with streamer. If not, see <https://www.gnu.org/licenses/>.
- */
-
-#ifdef USE_WAYLAND
-
-#include "capture_wlr.h"
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <wayland-client.h>
-
-#include "gpu.h"
-#include "toolbox/utils.h"
-#include "wlr-export-dmabuf-unstable-v1.h"
-
-struct CaptureContextWlr {
- struct GpuContext* gpu_context;
- const struct CaptureContextCallbacks* callbacks;
- void* user;
-
- // Wayland globals
- struct wl_display* wl_display;
- struct wl_registry* wl_registry;
- struct wl_output* wl_output;
- struct zwlr_export_dmabuf_manager_v1* zwlr_export_dmabuf_manager_v1;
-
- // Wayland dynamics
- struct zwlr_export_dmabuf_frame_v1* zwlr_export_dmabuf_frame_v1;
-
- // Volatile states
- uint32_t gpu_frame_width;
- uint32_t gpu_frame_height;
- uint32_t gpu_frame_fourcc;
- size_t gpu_frame_nplanes;
- struct GpuFramePlane gpu_frame_planes[4];
-};
-
-static bool CaptureOutput(struct CaptureContextWlr* capture_context);
-
-static void OnWlRegistryGlobal(void* data, struct wl_registry* wl_registry,
- uint32_t name, const char* interface,
- uint32_t version) {
-#define MAYBE_BIND(what) \
- if (!strcmp(interface, what##_interface.name)) do { \
- capture_context->what = \
- wl_registry_bind(wl_registry, name, &what##_interface, version); \
- if (!capture_context->what) \
- LOG("Failed to bind " #what " (%s)", strerror(errno)); \
- return; \
- } while (false)
- struct CaptureContextWlr* capture_context = data;
- if (!capture_context->wl_output) MAYBE_BIND(wl_output);
- MAYBE_BIND(zwlr_export_dmabuf_manager_v1);
-#undef MAYBE_BIND
-}
-
-static void OnWlRegistryGlobalRemove(void* data, struct wl_registry* registry,
- uint32_t name) {
- (void)data;
- (void)registry;
- (void)name;
-}
-
-static bool InitWaylandGlobals(struct CaptureContextWlr* capture_context) {
- capture_context->wl_display = wl_display_connect(NULL);
- if (!capture_context->wl_display) {
- LOG("Failed to connect wl_display (%s)", strerror(errno));
- return false;
- }
-
- capture_context->wl_registry =
- wl_display_get_registry(capture_context->wl_display);
- if (!capture_context->wl_registry) {
- LOG("Failed to get wl_registry (%s)", strerror(errno));
- goto rollback_wl_display;
- }
-
- static const struct wl_registry_listener wl_registry_listener = {
- .global = OnWlRegistryGlobal,
- .global_remove = OnWlRegistryGlobalRemove,
- };
- if (wl_registry_add_listener(capture_context->wl_registry,
- &wl_registry_listener, capture_context)) {
- LOG("Failed to add wl_registry listener (%s)", strerror(errno));
- goto rollback_wl_registry;
- }
- if (wl_display_roundtrip(capture_context->wl_display) == -1) {
- LOG("Failed to roundtrip wl_display (%s)", strerror(errno));
- goto rollback_wl_registry;
- }
-
- if (!capture_context->wl_output ||
- !capture_context->zwlr_export_dmabuf_manager_v1) {
- LOG("Some required wayland globals are missing");
- goto rollback_wayland_globals;
- }
- return true;
-
-rollback_wayland_globals:
- if (capture_context->zwlr_export_dmabuf_manager_v1)
- zwlr_export_dmabuf_manager_v1_destroy(
- capture_context->zwlr_export_dmabuf_manager_v1);
- if (capture_context->wl_output) wl_output_destroy(capture_context->wl_output);
-rollback_wl_registry:
- wl_registry_destroy(capture_context->wl_registry);
-rollback_wl_display:
- wl_display_disconnect(capture_context->wl_display);
- return false;
-}
-
-static void DeinitWaylandGlobals(struct CaptureContextWlr* capture_context) {
- zwlr_export_dmabuf_manager_v1_destroy(
- capture_context->zwlr_export_dmabuf_manager_v1);
- wl_output_destroy(capture_context->wl_output);
- wl_registry_destroy(capture_context->wl_registry);
- wl_display_disconnect(capture_context->wl_display);
-}
-
-static void OnExportDmabufFrameFrame(
- void* data, struct zwlr_export_dmabuf_frame_v1* zwlr_export_dmabuf_frame_v1,
- uint32_t width, uint32_t height, uint32_t offset_x, uint32_t offset_y,
- uint32_t buffer_flags, uint32_t flags, uint32_t format, uint32_t mod_high,
- uint32_t mod_low, uint32_t num_objects) {
- (void)zwlr_export_dmabuf_frame_v1;
- (void)offset_x;
- (void)offset_y;
- (void)buffer_flags;
- (void)flags;
- struct CaptureContextWlr* capture_context = data;
- capture_context->gpu_frame_width = width;
- capture_context->gpu_frame_height = height;
- capture_context->gpu_frame_fourcc = format;
- capture_context->gpu_frame_nplanes = num_objects;
- for (size_t i = 0; i < LENGTH(capture_context->gpu_frame_planes); i++) {
- capture_context->gpu_frame_planes[i].dmabuf_fd = -1;
- capture_context->gpu_frame_planes[i].modifier =
- (uint64_t)mod_high << 32 | mod_low;
- }
-}
-
-static void OnExportDmabufFrameObject(
- void* data, struct zwlr_export_dmabuf_frame_v1* zwlr_export_dmabuf_frame_v1,
- uint32_t index, int32_t fd, uint32_t size, uint32_t offset, uint32_t stride,
- uint32_t plane_index) {
- (void)zwlr_export_dmabuf_frame_v1;
- (void)size;
- (void)index;
- struct CaptureContextWlr* capture_context = data;
- capture_context->gpu_frame_planes[plane_index].dmabuf_fd = fd;
- capture_context->gpu_frame_planes[plane_index].pitch = stride;
- capture_context->gpu_frame_planes[plane_index].offset = offset;
-}
-
-static void OnExportDmabufFrameReady(
- void* data, struct zwlr_export_dmabuf_frame_v1* zwlr_export_dmabuf_frame_v1,
- uint32_t tv_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec) {
- (void)zwlr_export_dmabuf_frame_v1;
- (void)tv_sec_hi;
- (void)tv_sec_lo;
- (void)tv_nsec;
- struct CaptureContextWlr* capture_context = data;
-
- struct GpuFrame* gpu_frame = GpuContextCreateFrame(
- capture_context->gpu_context, capture_context->gpu_frame_width,
- capture_context->gpu_frame_height, capture_context->gpu_frame_fourcc,
- capture_context->gpu_frame_nplanes, capture_context->gpu_frame_planes);
- if (!gpu_frame) {
- // TODO(mburakov): ... then what?
- abort();
- }
-
- // TODO(mburakov): Callee could theoretically drop client, and then below code
- // in this function would probably fail miserably. Do something about this!
- capture_context->callbacks->OnFrameReady(capture_context->user, gpu_frame);
-
- CloseUniqueFds((int[4]){capture_context->gpu_frame_planes[0].dmabuf_fd,
- capture_context->gpu_frame_planes[1].dmabuf_fd,
- capture_context->gpu_frame_planes[2].dmabuf_fd,
- capture_context->gpu_frame_planes[3].dmabuf_fd});
- zwlr_export_dmabuf_frame_v1_destroy(
- capture_context->zwlr_export_dmabuf_frame_v1);
- capture_context->zwlr_export_dmabuf_frame_v1 = NULL;
-
- if (!CaptureOutput(capture_context)) {
- // TODO(mburakov): ... then what?
- abort();
- }
-}
-
-static void OnExportDmabufFrameCancel(
- void* data, struct zwlr_export_dmabuf_frame_v1* zwlr_export_dmabuf_frame_v1,
- uint32_t reason) {
- (void)zwlr_export_dmabuf_frame_v1;
- struct CaptureContextWlr* capture_context = data;
- CloseUniqueFds((int[4]){capture_context->gpu_frame_planes[0].dmabuf_fd,
- capture_context->gpu_frame_planes[1].dmabuf_fd,
- capture_context->gpu_frame_planes[2].dmabuf_fd,
- capture_context->gpu_frame_planes[3].dmabuf_fd});
- zwlr_export_dmabuf_frame_v1_destroy(
- capture_context->zwlr_export_dmabuf_frame_v1);
- capture_context->zwlr_export_dmabuf_frame_v1 = NULL;
- bool result;
- switch (reason) {
- case ZWLR_EXPORT_DMABUF_FRAME_V1_CANCEL_REASON_TEMPORARY:
- result = CaptureOutput(capture_context);
- break;
- case ZWLR_EXPORT_DMABUF_FRAME_V1_CANCEL_REASON_PERMANENT:
- result = false;
- break;
- case ZWLR_EXPORT_DMABUF_FRAME_V1_CANCEL_REASON_RESIZING:
- result = CaptureOutput(capture_context);
- break;
- default:
- __builtin_unreachable();
- }
- if (!result) {
- // TODO(mburakov): ... then what?
- abort();
- }
-}
-
-static bool CaptureOutput(struct CaptureContextWlr* capture_context) {
- capture_context->zwlr_export_dmabuf_frame_v1 =
- zwlr_export_dmabuf_manager_v1_capture_output(
- capture_context->zwlr_export_dmabuf_manager_v1, 1,
- capture_context->wl_output);
- if (!capture_context->zwlr_export_dmabuf_frame_v1) {
- LOG("Failed to capture zwlr_export_dmabuf_manager_v1 (%s)",
- strerror(errno));
- return false;
- }
-
- static const struct zwlr_export_dmabuf_frame_v1_listener
- zwlr_export_dmabuf_frame_v1_listener = {
- .frame = OnExportDmabufFrameFrame,
- .object = OnExportDmabufFrameObject,
- .ready = OnExportDmabufFrameReady,
- .cancel = OnExportDmabufFrameCancel,
- };
- if (zwlr_export_dmabuf_frame_v1_add_listener(
- capture_context->zwlr_export_dmabuf_frame_v1,
- &zwlr_export_dmabuf_frame_v1_listener, capture_context)) {
- LOG("Failed to add zwlr_export_dmabuf_frame_v1 listener (%s)",
- strerror(errno));
- goto rollback_frame;
- }
-
- if (wl_display_flush(capture_context->wl_display) == -1) {
- LOG("Failed to flush wl_display (%s)", strerror(errno));
- goto rollback_frame;
- }
- return true;
-
-rollback_frame:
- zwlr_export_dmabuf_frame_v1_destroy(
- capture_context->zwlr_export_dmabuf_frame_v1);
- capture_context->zwlr_export_dmabuf_frame_v1 = NULL;
- return false;
-}
-
-struct CaptureContextWlr* CaptureContextWlrCreate(
- struct GpuContext* gpu_context,
- const struct CaptureContextCallbacks* callbacks, void* user) {
- struct CaptureContextWlr* capture_context =
- malloc(sizeof(struct CaptureContextWlr));
- if (!capture_context) {
- LOG("Failed to allocate capture context (%s)", strerror(errno));
- return NULL;
- }
- *capture_context = (struct CaptureContextWlr){
- .gpu_context = gpu_context,
- .callbacks = callbacks,
- .user = user,
- };
-
- if (!InitWaylandGlobals(capture_context)) {
- LOG("Failed to initialize wayland globals");
- goto rollback_capture_context;
- }
- if (!CaptureOutput(capture_context)) {
- LOG("Failed to capture output");
- goto rollback_wayland_globals;
- }
- return capture_context;
-
-rollback_wayland_globals:
- DeinitWaylandGlobals(capture_context);
-rollback_capture_context:
- free(capture_context);
- return NULL;
-}
-
-int CaptureContextWlrGetEventsFd(struct CaptureContextWlr* capture_context) {
- int events_fd = wl_display_get_fd(capture_context->wl_display);
- if (events_fd == -1) LOG("Failed to get wl_display fd (%s)", strerror(errno));
- return events_fd;
-}
-
-bool CaptureContextWlrProcessEvents(struct CaptureContextWlr* capture_context) {
- bool result = wl_display_dispatch(capture_context->wl_display) != -1;
- if (!result) LOG("Failed to dispatch wl_display (%s)", strerror(errno));
- return result;
-}
-
-void CaptureContextWlrDestroy(struct CaptureContextWlr* capture_context) {
- if (capture_context->zwlr_export_dmabuf_frame_v1)
- zwlr_export_dmabuf_frame_v1_destroy(
- capture_context->zwlr_export_dmabuf_frame_v1);
- DeinitWaylandGlobals(capture_context);
- free(capture_context);
-}
-
-#endif // USE_WAYLAND