summaryrefslogtreecommitdiff
path: root/Kernel/Graphics/DisplayConnector.h
blob: ed218936c3fc155e4b5c40b864942bd89761fc37 (plain)
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/*
 * Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#pragma once

#include <AK/Types.h>
#include <Kernel/Devices/CharacterDevice.h>
#include <Kernel/Memory/SharedFramebufferVMObject.h>
#include <LibC/sys/ioctl_numbers.h>
#include <LibEDID/EDID.h>

namespace Kernel {

class GraphicsManagement;
class DisplayConnector : public CharacterDevice {
    friend class GraphicsManagement;
    friend class DeviceManagement;

public:
    struct ModeSetting {
        size_t horizontal_blanking_start() const
        {
            return horizontal_active;
        }
        size_t horizontal_sync_start() const
        {
            return horizontal_active + horizontal_front_porch_pixels;
        }
        size_t horizontal_sync_end() const
        {
            return horizontal_active + horizontal_front_porch_pixels + horizontal_sync_time_pixels;
        }
        size_t horizontal_total() const
        {
            return horizontal_active + horizontal_blank_pixels;
        }

        size_t vertical_blanking_start() const
        {
            return vertical_active;
        }
        size_t vertical_sync_start() const
        {
            return vertical_active + vertical_front_porch_lines;
        }
        size_t vertical_sync_end() const
        {
            return vertical_active + vertical_front_porch_lines + vertical_sync_time_lines;
        }
        size_t vertical_total() const
        {
            return vertical_active + vertical_blank_lines;
        }

        size_t horizontal_stride; // Note: This is commonly known as "pitch"
        size_t pixel_clock_in_khz;

        size_t horizontal_active;
        size_t horizontal_front_porch_pixels;
        size_t horizontal_sync_time_pixels;
        size_t horizontal_blank_pixels;

        size_t vertical_active;
        size_t vertical_front_porch_lines;
        size_t vertical_sync_time_lines;
        size_t vertical_blank_lines;

        size_t horizontal_offset; // Note: This is commonly known as "x offset"
        size_t vertical_offset;   // Note: This is commonly known as "y offset"
    };

public:
    enum class DisplayMode {
        Graphical,
        Console,
    };

public:
    virtual ~DisplayConnector() = default;

    virtual bool mutable_mode_setting_capable() const = 0;
    virtual bool double_framebuffering_capable() const = 0;
    virtual bool flush_support() const = 0;
    virtual bool partial_flush_support() const = 0;
    // Note: This can indicate to userland if the underlying hardware requires
    // a defined refresh rate being supplied when modesetting the screen resolution.
    // Paravirtualized hardware don't need such setting and can safely ignore this.
    virtual bool refresh_rate_support() const = 0;

    bool console_mode() const;
    ErrorOr<ByteBuffer> get_edid() const;
    virtual ErrorOr<void> set_mode_setting(ModeSetting const&) = 0;
    virtual ErrorOr<void> set_safe_mode_setting() = 0;
    ModeSetting current_mode_setting() const;
    virtual ErrorOr<void> set_y_offset(size_t y) = 0;
    virtual ErrorOr<void> unblank() = 0;

    void set_display_mode(Badge<GraphicsManagement>, DisplayMode);

    Memory::Region const& framebuffer_region() const { return *m_framebuffer_region; }

protected:
    void set_edid_bytes(Array<u8, 128> const& edid_bytes);

    DisplayConnector(PhysicalAddress framebuffer_address, size_t framebuffer_resource_size, bool enable_write_combine_optimization);
    DisplayConnector(size_t framebuffer_resource_size, bool enable_write_combine_optimization);
    virtual void enable_console() = 0;
    virtual void disable_console() = 0;
    virtual ErrorOr<void> flush_first_surface() = 0;
    virtual ErrorOr<void> flush_rectangle(size_t buffer_index, FBRect const& rect);

    ErrorOr<void> initialize_edid_for_generic_monitor(Optional<Array<u8, 3>> manufacturer_id_string);

    mutable Spinlock m_control_lock { LockRank::None };
    mutable Mutex m_flushing_lock;

    bool m_console_mode { false };

    bool m_vertical_offsetted { false };

    mutable Spinlock m_modeset_lock { LockRank::None };
    ModeSetting m_current_mode_setting {};

    Optional<EDID::Parser> m_edid_parser;
    EDID::Parser::RawBytes m_edid_bytes {};
    bool m_edid_valid { false };

    u8* framebuffer_data() { return m_framebuffer_data; }

private:
    // ^File
    virtual bool is_seekable() const override { return true; }
    virtual bool can_read(OpenFileDescription const&, u64) const final override { return true; }
    virtual bool can_write(OpenFileDescription const&, u64) const final override { return true; }
    virtual ErrorOr<size_t> read(OpenFileDescription&, u64, UserOrKernelBuffer&, size_t) override final;
    virtual ErrorOr<size_t> write(OpenFileDescription&, u64, UserOrKernelBuffer const&, size_t) override final;
    virtual ErrorOr<NonnullLockRefPtr<Memory::VMObject>> vmobject_for_mmap(Process&, Memory::VirtualRange const&, u64&, bool) override final;
    virtual ErrorOr<void> ioctl(OpenFileDescription&, unsigned request, Userspace<void*> arg) override final;
    virtual StringView class_name() const override final { return "DisplayConnector"sv; }

    DisplayConnector& operator=(DisplayConnector const&) = delete;
    DisplayConnector& operator=(DisplayConnector&&) = delete;
    DisplayConnector(DisplayConnector&&) = delete;

    virtual void will_be_destroyed() override;
    virtual void after_inserting() override;

    bool ioctl_requires_ownership(unsigned request) const;

    OwnPtr<Memory::Region> m_framebuffer_region;
    OwnPtr<Memory::Region> m_fake_writes_framebuffer_region;
    u8* m_framebuffer_data {};

    bool const m_enable_write_combine_optimization { false };
    bool const m_framebuffer_at_arbitrary_physical_range { false };

protected:
    Optional<PhysicalAddress> const m_framebuffer_address;
    size_t const m_framebuffer_resource_size;

private:
    LockRefPtr<Memory::SharedFramebufferVMObject> m_shared_framebuffer_vmobject;

    LockWeakPtr<Process> m_responsible_process;
    Spinlock m_responsible_process_lock { LockRank::None };

    IntrusiveListNode<DisplayConnector, LockRefPtr<DisplayConnector>> m_list_node;
};
}