diff options
author | Mikhail Burakov <mburakov@mailbox.org> | 2023-10-15 09:28:50 +0200 |
---|---|---|
committer | Mikhail Burakov <mburakov@mailbox.org> | 2023-10-15 16:36:02 +0200 |
commit | 9adec996efea0356547e797b36046103bec449e0 (patch) | |
tree | 456ee32048b38ba73085eb0487b1376088f320a7 | |
parent | 0e3c61abed24e2fec2148b22fe204e28074f1e90 (diff) |
Preparations for adding wlr capturing
-rw-r--r-- | .gitmodules | 3 | ||||
-rw-r--r-- | capture.c | 171 | ||||
-rw-r--r-- | capture.h | 14 | ||||
-rw-r--r-- | capture_kms.c | 226 | ||||
-rw-r--r-- | capture_kms.h | 32 | ||||
-rw-r--r-- | capture_wlr.h | 39 | ||||
-rw-r--r-- | main.c | 122 | ||||
-rw-r--r-- | makefile | 26 | ||||
m--------- | wlr-protocols | 0 |
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 @@ -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); } @@ -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_ @@ -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; } @@ -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 |