From 8d2a9518ef406f43caeb8bfea483949c7d93a903 Mon Sep 17 00:00:00 2001 From: Mikhail Burakov Date: Sat, 10 Aug 2024 10:59:02 +0200 Subject: Major rewrite of streamer (WIP) --- capture_kms.c | 225 ---------------------------------------------------------- 1 file changed, 225 deletions(-) delete mode 100644 capture_kms.c (limited to 'capture_kms.c') diff --git a/capture_kms.c b/capture_kms.c deleted file mode 100644 index fa46bd3..0000000 --- a/capture_kms.c +++ /dev/null @@ -1,225 +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 . - */ - -#include "capture_kms.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "gpu.h" -#include "toolbox/utils.h" - -static const int kCapturePeriod = 1000000000 / 60; - -struct CaptureContextKms { - 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); -} -- cgit v1.2.3