summaryrefslogtreecommitdiff
path: root/src/mode/framebuffer.cpp
blob: 46b98d133cd3a331d7ce534d3fba57edfd97728d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
/* SPDX-License-Identifier: MIT */

#include "drm++/mode/framebuffer.hpp"
#include "drm++/gem.hpp"
#include "drm++/helper/ioctl.hpp"
#include "drm++/helper/types.hpp"

#include <cassert>
#include <cstddef>
#include <optional>
#include <stdexcept>
#include <utility>
#include <vector>

#include <drm.h>
#include <drm_mode.h>

using namespace drm;
using namespace drm::mode;

Framebuffer::Framebuffer(
    int fd,
    u32 width,
    u32 height,
    u32 format,
    std::vector<ref<const gem::Object>> planes,
    std::vector<std::pair<u32, u32>> alignments,
    std::optional<u64> modifier,
    bool interlaced) : m_fd(fd),
        m_width(width), m_height(height), m_format(format),
        m_alignments(alignments), m_modifier(modifier), m_interlaced(interlaced
) {
    if (planes.empty() || planes.size() > 4 || planes.size() != alignments.size()) {
        throw std::invalid_argument("invalid number of planes");
    }

    drm_mode_fb_cmd2 args{
        .width = width,
        .height = height,
        .pixel_format = format,
        .flags = (modifier.has_value() ? DRM_MODE_FB_MODIFIERS : 0U)
            | (interlaced ? DRM_MODE_FB_INTERLACED : 0U)
    };
    for (size_t i = 0; i < planes.size(); ++i) {
        args.handles[i] = planes.at(i).get().handle();
        args.offsets[i] = alignments.at(i).first;
        args.pitches[i] = alignments.at(i).second;
        args.modifier[i] = modifier.value_or(0);
    }
    ioctl::perform(this->m_fd, DRM_IOCTL_MODE_ADDFB2, args);

    this->m_handle = args.fb_id;
}

void Framebuffer::destruct() noexcept {
    if (this->m_fd < 0) {
        return;
    }

    drm_mode_fb_cmd2 args{
        .fb_id = this->m_handle
    };
    try {
        ioctl::perform(this->m_fd, DRM_IOCTL_MODE_CLOSEFB, args);
    } catch (...) {
        assert(false && "Framebuffer close failed, memory leak likely");
    }

    this->m_fd = -1;
}