summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMikhail Burakov <mburakov@mailbox.org>2023-10-15 09:28:50 +0200
committerMikhail Burakov <mburakov@mailbox.org>2023-10-15 16:36:02 +0200
commit9adec996efea0356547e797b36046103bec449e0 (patch)
tree456ee32048b38ba73085eb0487b1376088f320a7
parent0e3c61abed24e2fec2148b22fe204e28074f1e90 (diff)
Preparations for adding wlr capturing
-rw-r--r--.gitmodules3
-rw-r--r--capture.c171
-rw-r--r--capture.h14
-rw-r--r--capture_kms.c226
-rw-r--r--capture_kms.h32
-rw-r--r--capture_wlr.h39
-rw-r--r--main.c122
-rw-r--r--makefile26
m---------wlr-protocols0
9 files changed, 412 insertions, 221 deletions
diff --git a/.gitmodules b/.gitmodules
index 1c21784..92e6233 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,6 @@
[submodule "toolbox"]
path = toolbox
url = https://burakov.eu/toolbox.git
+[submodule "wlr-protocols"]
+ path = wlr-protocols
+ url = https://gitlab.freedesktop.org/wlroots/wlr-protocols.git
diff --git a/capture.c b/capture.c
index f5283db..c0ea634 100644
--- a/capture.c
+++ b/capture.c
@@ -17,174 +17,61 @@
#include "capture.h"
-#include <assert.h>
#include <errno.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
-#include <xf86drm.h>
-#include "gpu.h"
+#include "capture_kms.h"
+#include "capture_wlr.h"
#include "toolbox/utils.h"
struct CaptureContext {
- struct GpuContext* gpu_context;
- int drm_fd;
- uint32_t crtc_id;
- struct GpuFrame* gpu_frame;
+ struct CaptureContextKms* kms;
+ struct CaptureContextWlr* wlr;
};
-static int OpenAnyModule(void) {
- static const char* const modules[] = {
- "i915", "amdgpu", "radeon", "nouveau", "vmwgfx",
- "omapdrm", "exynos", "tilcdc", "msm", "sti",
- "tegra", "imx-drm", "rockchip", "atmel-hlcdc", "fsl-dcu-drm",
- "vc4", "virtio_gpu", "mediatek", "meson", "pl111",
- "stm", "sun4i-drm", "armada-drm", "komeda", "imx-dcss",
- "mxsfb-drm", "simpledrm", "imx-lcdif", "vkms",
- };
- for (size_t i = 0; i < LENGTH(modules); i++) {
- int drm_fd = drmOpen(modules[i], NULL);
- if (drm_fd >= 0) return drm_fd;
- LOG("Failed to open %s (%s)", modules[i], strerror(errno));
- }
- return -1;
-}
-
-static bool GetCrtcFb(int drm_fd, uint32_t crtc_id,
- struct drm_mode_fb_cmd2* drm_mode_fb_cmd2) {
- struct drm_mode_crtc drm_mode_crtc = {
- .crtc_id = crtc_id,
- };
- if (drmIoctl(drm_fd, DRM_IOCTL_MODE_GETCRTC, &drm_mode_crtc)) {
- LOG("Failed to get crtc %u (%s)", crtc_id, strerror(errno));
- return false;
- }
- if (!drm_mode_crtc.fb_id) {
- LOG("Crtc %u has no framebuffer", crtc_id);
- return false;
- }
-
- struct drm_mode_fb_cmd2 result = {
- .fb_id = drm_mode_crtc.fb_id,
- };
- if (drmIoctl(drm_fd, DRM_IOCTL_MODE_GETFB2, &result)) {
- LOG("Failed to get framebuffer %u (%s)", drm_mode_crtc.fb_id,
- strerror(errno));
- return false;
- }
- if (!result.handles[0]) {
- LOG("Framebuffer %u has no handles", drm_mode_crtc.fb_id);
- return false;
- }
-
- if (drm_mode_fb_cmd2) *drm_mode_fb_cmd2 = result;
- return true;
-}
-
-struct CaptureContext* CaptureContextCreate(struct GpuContext* gpu_context) {
+struct CaptureContext* CaptureContextCreate(
+ struct GpuContext* gpu_context,
+ const struct CaptureContextCallbacks* callbacks, void* user) {
struct CaptureContext* capture_context =
- malloc(sizeof(struct CaptureContext));
+ calloc(1, sizeof(struct CaptureContext));
if (!capture_context) {
LOG("Failed to allocate capture context (%s)", strerror(errno));
return NULL;
}
- *capture_context = (struct CaptureContext){
- .gpu_context = gpu_context,
- .drm_fd = -1,
- };
- capture_context->drm_fd = OpenAnyModule();
- if (capture_context->drm_fd == -1) {
- LOG("Failed to open any module");
- goto rollback_capture_context;
- }
+ capture_context->kms = CaptureContextKmsCreate(gpu_context, callbacks, user);
+ if (capture_context->kms) return capture_context;
- uint32_t crtc_ids[16];
- struct drm_mode_card_res drm_mode_card_res = {
- .crtc_id_ptr = (uintptr_t)crtc_ids,
- .count_crtcs = LENGTH(crtc_ids),
- };
- if (drmIoctl(capture_context->drm_fd, DRM_IOCTL_MODE_GETRESOURCES,
- &drm_mode_card_res)) {
- LOG("Failed to get drm mode resources (%s)", strerror(errno));
- goto rollback_drm_fd;
- }
- for (size_t i = 0; i < drm_mode_card_res.count_crtcs; i++) {
- if (GetCrtcFb(capture_context->drm_fd, crtc_ids[i], NULL)) {
- LOG("Capturing crtc %u", crtc_ids[i]);
- capture_context->crtc_id = crtc_ids[i];
- return capture_context;
- }
- }
- LOG("Nothing to capture");
+ LOG("Failed to create kms capture context");
+ capture_context->wlr = CaptureContextWlrCreate(gpu_context, callbacks, user);
+ if (capture_context->wlr) return capture_context;
-rollback_drm_fd:
- drmClose(capture_context->drm_fd);
-rollback_capture_context:
+ LOG("Failed to create wlr capture context");
free(capture_context);
return NULL;
}
-const struct GpuFrame* CaptureContextGetFrame(
- struct CaptureContext* capture_context) {
- struct drm_mode_fb_cmd2 drm_mode_fb_cmd2;
- if (!GetCrtcFb(capture_context->drm_fd, capture_context->crtc_id,
- &drm_mode_fb_cmd2))
- return NULL;
-
- if (capture_context->gpu_frame) {
- GpuContextDestroyFrame(capture_context->gpu_context,
- capture_context->gpu_frame);
- capture_context->gpu_frame = NULL;
- }
-
- struct GpuFramePlane planes[] = {
- {.dmabuf_fd = -1},
- {.dmabuf_fd = -1},
- {.dmabuf_fd = -1},
- {.dmabuf_fd = -1},
- };
- static_assert(LENGTH(planes) == LENGTH(drm_mode_fb_cmd2.handles),
- "Suspicious drm_mode_fb_cmd2 structure");
-
- size_t nplanes = 0;
- for (; nplanes < LENGTH(planes); nplanes++) {
- if (!drm_mode_fb_cmd2.handles[nplanes]) break;
- int status = drmPrimeHandleToFD(capture_context->drm_fd,
- drm_mode_fb_cmd2.handles[nplanes], 0,
- &planes[nplanes].dmabuf_fd);
- if (status) {
- LOG("Failed to get dmabuf fd (%d)", status);
- goto release_planes;
- }
- planes[nplanes].offset = drm_mode_fb_cmd2.offsets[nplanes];
- planes[nplanes].pitch = drm_mode_fb_cmd2.pitches[nplanes];
- planes[nplanes].modifier = drm_mode_fb_cmd2.modifier[nplanes];
- }
-
- capture_context->gpu_frame = GpuContextCreateFrame(
- capture_context->gpu_context, drm_mode_fb_cmd2.width,
- drm_mode_fb_cmd2.height, drm_mode_fb_cmd2.pixel_format, nplanes, planes);
- if (!capture_context->gpu_frame) {
- LOG("Failed to create gpu frame");
- goto release_planes;
- }
- return capture_context->gpu_frame;
+int CaptureContextGetEventsFd(struct CaptureContext* capture_context) {
+ if (capture_context->kms)
+ return CaptureContextKmsGetEventsFd(capture_context->kms);
+ if (capture_context->wlr)
+ return CaptureContextWlrGetEventsFd(capture_context->wlr);
+ return -1;
+}
-release_planes:
- CloseUniqueFds((int[]){planes[0].dmabuf_fd, planes[1].dmabuf_fd,
- planes[2].dmabuf_fd, planes[3].dmabuf_fd});
- return NULL;
+bool CaptureContextProcessEvents(struct CaptureContext* capture_context) {
+ if (capture_context->kms)
+ return CaptureContextKmsProcessEvents(capture_context->kms);
+ if (capture_context->wlr)
+ return CaptureContextWlrProcessEvents(capture_context->wlr);
+ return false;
}
void CaptureContextDestroy(struct CaptureContext* capture_context) {
- if (capture_context->gpu_frame) {
- GpuContextDestroyFrame(capture_context->gpu_context,
- capture_context->gpu_frame);
- }
- drmClose(capture_context->drm_fd);
+ if (capture_context->wlr) CaptureContextWlrDestroy(capture_context->wlr);
+ if (capture_context->kms) CaptureContextKmsDestroy(capture_context->kms);
free(capture_context);
}
diff --git a/capture.h b/capture.h
index 7b0b60d..a56a5d2 100644
--- a/capture.h
+++ b/capture.h
@@ -18,13 +18,21 @@
#ifndef STREAMER_CAPTURE_H_
#define STREAMER_CAPTURE_H_
+#include <stdbool.h>
+
struct CaptureContext;
struct GpuContext;
struct GpuFrame;
-struct CaptureContext* CaptureContextCreate(struct GpuContext* gpu_context);
-const struct GpuFrame* CaptureContextGetFrame(
- struct CaptureContext* capture_context);
+struct CaptureContextCallbacks {
+ void (*OnFrameReady)(void* user, const struct GpuFrame* gpu_frame);
+};
+
+struct CaptureContext* CaptureContextCreate(
+ struct GpuContext* gpu_context,
+ const struct CaptureContextCallbacks* callbacks, void* user);
+int CaptureContextGetEventsFd(struct CaptureContext* capture_context);
+bool CaptureContextProcessEvents(struct CaptureContext* capture_context);
void CaptureContextDestroy(struct CaptureContext* capture_context);
#endif // STREAMER_CAPTURE_H_
diff --git a/capture_kms.c b/capture_kms.c
new file mode 100644
index 0000000..52742e8
--- /dev/null
+++ b/capture_kms.c
@@ -0,0 +1,226 @@
+/*
+ * 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/>.
+ */
+
+#include "capture_kms.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/timerfd.h>
+#include <time.h>
+#include <unistd.h>
+#include <xf86drm.h>
+
+#include "gpu.h"
+#include "toolbox/utils.h"
+
+static const int kCapturePeriod = 1000000000 / 60;
+
+struct CaptureContextKms {
+ struct IoMuxer* io_muxer;
+ struct GpuContext* gpu_context;
+ const struct CaptureContextCallbacks* callbacks;
+ void* user;
+
+ int drm_fd;
+ uint32_t crtc_id;
+ int timer_fd;
+};
+
+static int OpenAnyModule(void) {
+ static const char* const modules[] = {
+ "i915",
+ "amdgpu",
+ };
+ for (size_t i = 0; i < LENGTH(modules); i++) {
+ int drm_fd = drmOpen(modules[i], NULL);
+ if (drm_fd >= 0) return drm_fd;
+ LOG("Failed to open %s (%s)", modules[i], strerror(errno));
+ }
+ return -1;
+}
+
+static bool GetCrtcFb(int drm_fd, uint32_t crtc_id,
+ struct drm_mode_fb_cmd2* drm_mode_fb_cmd2) {
+ struct drm_mode_crtc drm_mode_crtc = {
+ .crtc_id = crtc_id,
+ };
+ if (drmIoctl(drm_fd, DRM_IOCTL_MODE_GETCRTC, &drm_mode_crtc)) {
+ LOG("Failed to get crtc %u (%s)", crtc_id, strerror(errno));
+ return false;
+ }
+ if (!drm_mode_crtc.fb_id) {
+ LOG("Crtc %u has no framebuffer", crtc_id);
+ return false;
+ }
+
+ struct drm_mode_fb_cmd2 result = {
+ .fb_id = drm_mode_crtc.fb_id,
+ };
+ if (drmIoctl(drm_fd, DRM_IOCTL_MODE_GETFB2, &result)) {
+ LOG("Failed to get framebuffer %u (%s)", drm_mode_crtc.fb_id,
+ strerror(errno));
+ return false;
+ }
+ if (!result.handles[0]) {
+ LOG("Framebuffer %u has no handles", drm_mode_crtc.fb_id);
+ return false;
+ }
+
+ if (drm_mode_fb_cmd2) *drm_mode_fb_cmd2 = result;
+ return true;
+}
+
+struct CaptureContextKms* CaptureContextKmsCreate(
+ struct GpuContext* gpu_context,
+ const struct CaptureContextCallbacks* callbacks, void* user) {
+ struct CaptureContextKms* capture_context =
+ malloc(sizeof(struct CaptureContextKms));
+ if (!capture_context) {
+ LOG("Failed to allocate capture context (%s)", strerror(errno));
+ return NULL;
+ }
+ *capture_context = (struct CaptureContextKms){
+ .gpu_context = gpu_context,
+ .callbacks = callbacks,
+ .user = user,
+ .drm_fd = -1,
+ .timer_fd = -1,
+ };
+
+ capture_context->drm_fd = OpenAnyModule();
+ if (capture_context->drm_fd == -1) {
+ LOG("Failed to open any module");
+ goto rollback_capture_context;
+ }
+
+ uint32_t crtc_ids[16];
+ struct drm_mode_card_res drm_mode_card_res = {
+ .crtc_id_ptr = (uintptr_t)crtc_ids,
+ .count_crtcs = LENGTH(crtc_ids),
+ };
+ if (drmIoctl(capture_context->drm_fd, DRM_IOCTL_MODE_GETRESOURCES,
+ &drm_mode_card_res)) {
+ LOG("Failed to get drm mode resources (%s)", strerror(errno));
+ goto rollback_drm_fd;
+ }
+ for (size_t i = 0; i < drm_mode_card_res.count_crtcs; i++) {
+ if (GetCrtcFb(capture_context->drm_fd, crtc_ids[i], NULL)) {
+ LOG("Capturing crtc %u", crtc_ids[i]);
+ capture_context->crtc_id = crtc_ids[i];
+ break;
+ }
+ }
+ if (!capture_context->crtc_id) {
+ LOG("Nothing to capture");
+ goto rollback_drm_fd;
+ }
+
+ capture_context->timer_fd = timerfd_create(CLOCK_MONOTONIC, 0);
+ if (capture_context->timer_fd == -1) {
+ LOG("Failed to create timer (%s)", strerror(errno));
+ goto rollback_drm_fd;
+ }
+ static const struct itimerspec kTimerSpec = {
+ .it_interval.tv_nsec = kCapturePeriod,
+ .it_value.tv_nsec = kCapturePeriod,
+ };
+ if (timerfd_settime(capture_context->timer_fd, 0, &kTimerSpec, NULL)) {
+ LOG("Failed to arm timer (%s)", strerror(errno));
+ goto rollback_timer_fd;
+ }
+ return capture_context;
+
+rollback_timer_fd:
+ close(capture_context->timer_fd);
+rollback_drm_fd:
+ drmClose(capture_context->drm_fd);
+rollback_capture_context:
+ free(capture_context);
+ return NULL;
+}
+
+int CaptureContextKmsGetEventsFd(struct CaptureContextKms* capture_context) {
+ return capture_context->timer_fd;
+}
+
+bool CaptureContextKmsProcessEvents(struct CaptureContextKms* capture_context) {
+ uint64_t expirations;
+ if (read(capture_context->timer_fd, &expirations, sizeof(expirations)) !=
+ sizeof(expirations)) {
+ LOG("Failed to read timer expirations (%s)", strerror(errno));
+ return false;
+ }
+
+ struct drm_mode_fb_cmd2 drm_mode_fb_cmd2;
+ if (!GetCrtcFb(capture_context->drm_fd, capture_context->crtc_id,
+ &drm_mode_fb_cmd2)) {
+ return false;
+ }
+
+ struct GpuFramePlane planes[] = {
+ {.dmabuf_fd = -1},
+ {.dmabuf_fd = -1},
+ {.dmabuf_fd = -1},
+ {.dmabuf_fd = -1},
+ };
+ static_assert(LENGTH(planes) == LENGTH(drm_mode_fb_cmd2.handles),
+ "Suspicious drm_mode_fb_cmd2 structure");
+
+ size_t nplanes = 0;
+ for (; nplanes < LENGTH(planes); nplanes++) {
+ if (!drm_mode_fb_cmd2.handles[nplanes]) break;
+ int status = drmPrimeHandleToFD(capture_context->drm_fd,
+ drm_mode_fb_cmd2.handles[nplanes], 0,
+ &planes[nplanes].dmabuf_fd);
+ if (status) {
+ LOG("Failed to get dmabuf fd (%d)", status);
+ goto release_planes;
+ }
+ planes[nplanes].offset = drm_mode_fb_cmd2.offsets[nplanes];
+ planes[nplanes].pitch = drm_mode_fb_cmd2.pitches[nplanes];
+ planes[nplanes].modifier = drm_mode_fb_cmd2.modifier[nplanes];
+ }
+
+ struct GpuFrame* gpu_frame = GpuContextCreateFrame(
+ capture_context->gpu_context, drm_mode_fb_cmd2.width,
+ drm_mode_fb_cmd2.height, drm_mode_fb_cmd2.pixel_format, nplanes, planes);
+ if (!gpu_frame) {
+ LOG("Failed to create gpu frame");
+ goto release_planes;
+ }
+
+ // mburakov: Capture context might get destroyed in callback.
+ struct GpuContext* gpu_context = capture_context->gpu_context;
+ capture_context->callbacks->OnFrameReady(capture_context->user, gpu_frame);
+ GpuContextDestroyFrame(gpu_context, gpu_frame);
+ return true;
+
+release_planes:
+ CloseUniqueFds((int[]){planes[0].dmabuf_fd, planes[1].dmabuf_fd,
+ planes[2].dmabuf_fd, planes[3].dmabuf_fd});
+ return false;
+}
+
+void CaptureContextKmsDestroy(struct CaptureContextKms* capture_context) {
+ close(capture_context->timer_fd);
+ drmClose(capture_context->drm_fd);
+ free(capture_context);
+}
diff --git a/capture_kms.h b/capture_kms.h
new file mode 100644
index 0000000..52531d2
--- /dev/null
+++ b/capture_kms.h
@@ -0,0 +1,32 @@
+/*
+ * 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/>.
+ */
+
+#ifndef STREAMER_CAPTURE_KMS_H_
+#define STREAMER_CAPTURE_KMS_H_
+
+#include "capture.h"
+
+struct CaptureContextKms;
+
+struct CaptureContextKms* CaptureContextKmsCreate(
+ struct GpuContext* gpu_context,
+ const struct CaptureContextCallbacks* callbacks, void* user);
+int CaptureContextKmsGetEventsFd(struct CaptureContextKms* capture_context);
+bool CaptureContextKmsProcessEvents(struct CaptureContextKms* capture_context);
+void CaptureContextKmsDestroy(struct CaptureContextKms* capture_context);
+
+#endif // STREAMER_CAPTURE_KMS_H_
diff --git a/capture_wlr.h b/capture_wlr.h
new file mode 100644
index 0000000..8c732a3
--- /dev/null
+++ b/capture_wlr.h
@@ -0,0 +1,39 @@
+/*
+ * 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/>.
+ */
+
+#ifndef STREAMER_CAPTURE_WLR_H_
+#define STREAMER_CAPTURE_WLR_H_
+
+#include "capture.h"
+
+struct CaptureContextWlr;
+
+#ifdef USE_WAYLAND
+struct CaptureContextWlr* CaptureContextWlrCreate(
+ struct GpuContext* gpu_context,
+ const struct CaptureContextCallbacks* callbacks, void* user);
+int CaptureContextWlrGetEventsFd(struct CaptureContextWlr* capture_context);
+bool CaptureContextWlrProcessEvents(struct CaptureContextWlr* capture_context);
+void CaptureContextWlrDestroy(struct CaptureContextWlr* capture_context);
+#else // USE_WAYLAND
+#define CaptureContextWlrCreate(...) NULL
+#define CaptureContextWlrGetEventsFd(...) -1
+#define CaptureContextWlrProcessEvents(...) false
+#define CaptureContextWlrDestroy(...)
+#endif // USE_WAYLAND
+
+#endif // STREAMER_CAPTURE_WLR_H_
diff --git a/main.c b/main.c
index bc737fc..2e0ddc4 100644
--- a/main.c
+++ b/main.c
@@ -22,8 +22,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/timerfd.h>
-#include <time.h>
#include <unistd.h>
#include "capture.h"
@@ -41,20 +39,18 @@
// https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/183
static const enum YuvColorspace colorspace = kItuRec601;
static const enum YuvRange range = kNarrowRange;
-static const int capture_period = 1000000000 / 60;
static volatile sig_atomic_t g_signal;
static void OnSignal(int status) { g_signal = status; }
struct Contexts {
+ struct GpuContext* gpu_context;
struct IoMuxer io_muxer;
- int timer_fd;
int server_fd;
- struct GpuContext* gpu_context;
- struct CaptureContext* capture_context;
int client_fd;
struct InputHandler* input_handler;
+ struct CaptureContext* capture_context;
struct EncodeContext* encode_context;
};
@@ -93,11 +89,14 @@ rollback_sock:
}
static void MaybeDropClient(struct Contexts* contexts) {
- static const struct itimerspec spec = {0};
if (contexts->encode_context) {
EncodeContextDestroy(contexts->encode_context);
contexts->encode_context = NULL;
}
+ if (contexts->capture_context) {
+ CaptureContextDestroy(contexts->capture_context);
+ contexts->capture_context = NULL;
+ }
if (contexts->input_handler) {
IoMuxerForget(&contexts->io_muxer,
InputHandlerGetEventsFd(contexts->input_handler));
@@ -111,38 +110,10 @@ static void MaybeDropClient(struct Contexts* contexts) {
}
}
-static void OnTimerExpire(void* user) {
+static void OnCaptureContextFrameReady(void* user,
+ const struct GpuFrame* captured_frame) {
struct Contexts* contexts = user;
- if (!IoMuxerOnRead(&contexts->io_muxer, contexts->timer_fd, &OnTimerExpire,
- user)) {
- LOG("Failed to reschedule timer (%s)", strerror(errno));
- g_signal = SIGABRT;
- return;
- }
- uint64_t expirations;
- if (read(contexts->timer_fd, &expirations, sizeof(expirations)) !=
- sizeof(expirations)) {
- LOG("Failed to read timer expirations (%s)", strerror(errno));
- g_signal = SIGABRT;
- return;
- }
- if (contexts->client_fd == -1) {
- // mburakov: Timer must disarm itself AFTER reading.
- static const struct itimerspec spec = {0};
- if (timerfd_settime(contexts->timer_fd, 0, &spec, NULL)) {
- LOG("Failed to disarm timer (%s)", strerror(errno));
- g_signal = SIGABRT;
- }
- return;
- }
-
unsigned long long timestamp = MicrosNow();
- const struct GpuFrame* captured_frame =
- CaptureContextGetFrame(contexts->capture_context);
- if (!captured_frame) {
- LOG("Failed to capture frame");
- goto drop_client;
- }
if (!contexts->encode_context) {
contexts->encode_context =
@@ -198,11 +169,29 @@ static void OnInputEvents(void* user) {
if (!IoMuxerOnRead(&contexts->io_muxer,
InputHandlerGetEventsFd(contexts->input_handler),
&OnInputEvents, user)) {
- LOG("Failed to reschedule events reading (%s)", strerror(errno));
+ LOG("Failed to reschedule input events reading (%s)", strerror(errno));
goto drop_client;
}
if (!InputHandlerProcessEvents(contexts->input_handler)) {
- LOG("Failed to process events");
+ LOG("Failed to process input events");
+ goto drop_client;
+ }
+ return;
+
+drop_client:
+ MaybeDropClient(contexts);
+}
+
+static void OnCaptureContextEvents(void* user) {
+ struct Contexts* contexts = user;
+ if (!IoMuxerOnRead(&contexts->io_muxer,
+ CaptureContextGetEventsFd(contexts->capture_context),
+ &OnCaptureContextEvents, user)) {
+ LOG("Failed to reschedule capture events reading (%s)", strerror(errno));
+ goto drop_client;
+ }
+ if (!CaptureContextProcessEvents(contexts->capture_context)) {
+ LOG("Failed to process capture events");
goto drop_client;
}
return;
@@ -246,15 +235,22 @@ static void OnClientConnecting(void* user) {
if (!IoMuxerOnRead(&contexts->io_muxer,
InputHandlerGetEventsFd(contexts->input_handler),
&OnInputEvents, user)) {
- LOG("Failed to schedule events reading (%s)", strerror(errno));
+ LOG("Failed to schedule input events reading (%s)", strerror(errno));
goto drop_client;
}
- static const struct itimerspec spec = {
- .it_interval.tv_nsec = capture_period,
- .it_value.tv_nsec = capture_period,
+ static const struct CaptureContextCallbacks kCaptureContextCallbacks = {
+ .OnFrameReady = OnCaptureContextFrameReady,
};
- if (timerfd_settime(contexts->timer_fd, 0, &spec, NULL)) {
- LOG("Failed to arm timer (%s)", strerror(errno));
+ contexts->capture_context = CaptureContextCreate(
+ contexts->gpu_context, &kCaptureContextCallbacks, user);
+ if (!contexts->capture_context) {
+ LOG("Failed to create capture context");
+ goto drop_client;
+ }
+ if (!IoMuxerOnRead(&contexts->io_muxer,
+ CaptureContextGetEventsFd(contexts->capture_context),
+ &OnCaptureContextEvents, user)) {
+ LOG("Failed to schedule capture events reading (%s)", strerror(errno));
goto drop_client;
}
return;
@@ -276,41 +272,24 @@ int main(int argc, char* argv[]) {
}
struct Contexts contexts = {
- .timer_fd = -1,
.server_fd = -1,
.client_fd = -1,
};
+ contexts.gpu_context = GpuContextCreate(colorspace, range);
+ if (!contexts.gpu_context) {
+ LOG("Failed to create gpu context");
+ return EXIT_FAILURE;
+ }
IoMuxerCreate(&contexts.io_muxer);
contexts.server_fd = CreateServerSocket(argv[1]);
if (contexts.server_fd == -1) {
LOG("Failed to create server socket");
goto rollback_io_muxer;
}
- contexts.timer_fd = timerfd_create(CLOCK_MONOTONIC, 0);
- if (contexts.timer_fd == -1) {
- LOG("Failed to create timer (%s)", strerror(errno));
- goto rollback_server_fd;
- }
- contexts.gpu_context = GpuContextCreate(colorspace, range);
- if (!contexts.gpu_context) {
- LOG("Failed to create gpu context");
- goto rollback_timer_fd;
- }
- contexts.capture_context = CaptureContextCreate(contexts.gpu_context);
- if (!contexts.capture_context) {
- LOG("Failed to create capture context");
- goto rollback_gpu_context;
- }
-
- if (!IoMuxerOnRead(&contexts.io_muxer, contexts.timer_fd, &OnTimerExpire,
- &contexts)) {
- LOG("Failed to schedule timer (%s)", strerror(errno));
- goto rollback_capture_context;
- }
if (!IoMuxerOnRead(&contexts.io_muxer, contexts.server_fd,
&OnClientConnecting, &contexts)) {
LOG("Failed to schedule accept (%s)", strerror(errno));
- goto rollback_capture_context;
+ goto rollback_server_fd;
}
while (!g_signal) {
if (IoMuxerIterate(&contexts.io_muxer, -1) && errno != EINTR) {
@@ -320,16 +299,11 @@ int main(int argc, char* argv[]) {
}
MaybeDropClient(&contexts);
-rollback_capture_context:
- CaptureContextDestroy(contexts.capture_context);
-rollback_gpu_context:
- GpuContextDestroy(contexts.gpu_context);
-rollback_timer_fd:
- close(contexts.timer_fd);
rollback_server_fd:
close(contexts.server_fd);
rollback_io_muxer:
IoMuxerDestroy(&contexts.io_muxer);
+ GpuContextDestroy(contexts.gpu_context);
bool result = g_signal == SIGINT || g_signal == SIGTERM;
return result ? EXIT_SUCCESS : EXIT_FAILURE;
}
diff --git a/makefile b/makefile
index 8a920d2..6785689 100644
--- a/makefile
+++ b/makefile
@@ -15,11 +15,24 @@ libs:=\
libva \
libva-drm
+protocols_dir:=\
+ wlr-protocols/unstable
+
+protocols:=\
+ wlr-export-dmabuf-unstable-v1
+
res:=\
vertex.glsl \
luma.glsl \
chroma.glsl
+ifdef USE_WAYLAND
+ obj:=$(patsubst %,%.o,$(protocols)) $(obj)
+ headers:=$(patsubst %,%.h,$(protocols))
+ libs+=wayland-client
+ CFLAGS+=-DUSE_WAYLAND
+endif
+
#CFLAGS+=-DUSE_EGL_MESA_PLATFORM_SURFACELESS
CFLAGS+=$(shell pkg-config --cflags $(libs))
LDFLAGS+=$(shell pkg-config --libs $(libs))
@@ -35,10 +48,19 @@ all: $(bin)
$(bin): $(obj)
$(CC) $^ $(LDFLAGS) -o $@
-%.o: %.c *.h $(res)
+%.o: %.c *.h $(res) $(headers)
$(CC) -c $< $(CFLAGS) -o $@
+%.h: $(protocols_dir)/%.xml
+ wayland-scanner client-header $< $@
+
+%.c: $(protocols_dir)/%.xml
+ wayland-scanner private-code $< $@
+
clean:
- -rm $(bin) $(obj)
+ -rm $(bin) $(obj) $(headers) \
+ $(foreach proto,$(protocols),$(proto).h $(proto).o)
.PHONY: all clean
+
+.PRECIOUS: $(headers)
diff --git a/wlr-protocols b/wlr-protocols
new file mode 160000
+Subproject 4264185db3b7e961e7f157e1cc4fd0ab7513756