mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 00:57:45 +00:00
DisplaySettings+WindowServer: Add support for display connector devices
This commit is contained in:
parent
e6ebf9e5c1
commit
d9a2706079
12 changed files with 308 additions and 38 deletions
|
@ -18,11 +18,13 @@ ALWAYS_INLINE int fb_get_properties(int fd, FBProperties* info)
|
||||||
return ioctl(fd, FB_IOCTL_GET_PROPERTIES, info);
|
return ioctl(fd, FB_IOCTL_GET_PROPERTIES, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: Remove this once framebuffer devices are removed.
|
||||||
ALWAYS_INLINE int fb_get_head_properties(int fd, FBHeadProperties* info)
|
ALWAYS_INLINE int fb_get_head_properties(int fd, FBHeadProperties* info)
|
||||||
{
|
{
|
||||||
return ioctl(fd, FB_IOCTL_GET_HEAD_PROPERTIES, info);
|
return ioctl(fd, FB_IOCTL_GET_HEAD_PROPERTIES, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: Remove this once framebuffer devices are removed.
|
||||||
ALWAYS_INLINE int fb_get_resolution(int fd, FBHeadResolution* info)
|
ALWAYS_INLINE int fb_get_resolution(int fd, FBHeadResolution* info)
|
||||||
{
|
{
|
||||||
FBHeadProperties head_properties;
|
FBHeadProperties head_properties;
|
||||||
|
@ -36,6 +38,7 @@ ALWAYS_INLINE int fb_get_resolution(int fd, FBHeadResolution* info)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: Remove this once framebuffer devices are removed.
|
||||||
ALWAYS_INLINE int fb_set_resolution(int fd, FBHeadResolution* info)
|
ALWAYS_INLINE int fb_set_resolution(int fd, FBHeadResolution* info)
|
||||||
{
|
{
|
||||||
return ioctl(fd, FB_IOCTL_SET_HEAD_RESOLUTION, info);
|
return ioctl(fd, FB_IOCTL_SET_HEAD_RESOLUTION, info);
|
||||||
|
@ -56,6 +59,31 @@ ALWAYS_INLINE int fb_set_head_vertical_offset_buffer(int fd, FBHeadVerticalOffse
|
||||||
return ioctl(fd, FB_IOCTL_SET_HEAD_VERTICAL_OFFSET_BUFFER, vertical_offset);
|
return ioctl(fd, FB_IOCTL_SET_HEAD_VERTICAL_OFFSET_BUFFER, vertical_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE int fb_set_head_mode_setting(int fd, FBHeadModeSetting* mode_setting)
|
||||||
|
{
|
||||||
|
return ioctl(fd, FB_IOCTL_SET_HEAD_MODE_SETTING, mode_setting);
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE int fb_get_head_mode_setting(int fd, FBHeadModeSetting* mode_setting)
|
||||||
|
{
|
||||||
|
FBHeadModeSetting head_mode_setting;
|
||||||
|
if (auto rc = ioctl(fd, FB_IOCTL_GET_HEAD_MODE_SETTING, &head_mode_setting); rc < 0)
|
||||||
|
return rc;
|
||||||
|
mode_setting->horizontal_stride = head_mode_setting.horizontal_stride;
|
||||||
|
mode_setting->pixel_clock_in_khz = head_mode_setting.pixel_clock_in_khz;
|
||||||
|
mode_setting->horizontal_active = head_mode_setting.horizontal_active;
|
||||||
|
mode_setting->horizontal_front_porch_pixels = head_mode_setting.horizontal_front_porch_pixels;
|
||||||
|
mode_setting->horizontal_sync_time_pixels = head_mode_setting.horizontal_sync_time_pixels;
|
||||||
|
mode_setting->horizontal_blank_pixels = head_mode_setting.horizontal_blank_pixels;
|
||||||
|
mode_setting->vertical_active = head_mode_setting.vertical_active;
|
||||||
|
mode_setting->vertical_front_porch_lines = head_mode_setting.vertical_front_porch_lines;
|
||||||
|
mode_setting->vertical_sync_time_lines = head_mode_setting.vertical_sync_time_lines;
|
||||||
|
mode_setting->vertical_blank_lines = head_mode_setting.vertical_blank_lines;
|
||||||
|
mode_setting->horizontal_offset = head_mode_setting.horizontal_offset;
|
||||||
|
mode_setting->vertical_offset = head_mode_setting.vertical_offset;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE int fb_flush_buffers(int fd, int index, FBRect const* rects, unsigned count)
|
ALWAYS_INLINE int fb_flush_buffers(int fd, int index, FBRect const* rects, unsigned count)
|
||||||
{
|
{
|
||||||
FBFlushRects fb_flush_rects;
|
FBFlushRects fb_flush_rects;
|
||||||
|
|
|
@ -148,7 +148,8 @@ void MonitorSettingsWidget::load_current_settings()
|
||||||
size_t virtual_screen_count = 0;
|
size_t virtual_screen_count = 0;
|
||||||
for (size_t i = 0; i < m_screen_layout.screens.size(); i++) {
|
for (size_t i = 0; i < m_screen_layout.screens.size(); i++) {
|
||||||
String screen_display_name;
|
String screen_display_name;
|
||||||
if (m_screen_layout.screens[i].mode == WindowServer::ScreenLayout::Screen::Mode::Device) {
|
if (m_screen_layout.screens[i].mode == WindowServer::ScreenLayout::Screen::Mode::Device
|
||||||
|
|| m_screen_layout.screens[i].mode == WindowServer::ScreenLayout::Screen::Mode::DisplayConnectorDevice) {
|
||||||
if (auto edid = EDID::Parser::from_framebuffer_device(m_screen_layout.screens[i].device.value(), 0); !edid.is_error()) { // TODO: multihead
|
if (auto edid = EDID::Parser::from_framebuffer_device(m_screen_layout.screens[i].device.value(), 0); !edid.is_error()) { // TODO: multihead
|
||||||
screen_display_name = display_name_from_edid(edid.value());
|
screen_display_name = display_name_from_edid(edid.value());
|
||||||
m_screen_edids.append(edid.release_value());
|
m_screen_edids.append(edid.release_value());
|
||||||
|
|
|
@ -26,6 +26,7 @@ struct FBProperties {
|
||||||
unsigned char refresh_rate_support;
|
unsigned char refresh_rate_support;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// FIXME: Remove this once framebuffer devices are removed.
|
||||||
struct FBHeadProperties {
|
struct FBHeadProperties {
|
||||||
int head_index;
|
int head_index;
|
||||||
|
|
||||||
|
@ -52,6 +53,7 @@ struct FBHeadModeSetting {
|
||||||
int vertical_offset;
|
int vertical_offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// FIXME: Remove this once framebuffer devices are removed.
|
||||||
struct FBHeadResolution {
|
struct FBHeadResolution {
|
||||||
int head_index;
|
int head_index;
|
||||||
int pitch;
|
int pitch;
|
||||||
|
@ -181,6 +183,9 @@ enum IOCtlNumber {
|
||||||
#define FB_IOCTL_GET_HEAD_VERTICAL_OFFSET_BUFFER FB_IOCTL_GET_HEAD_VERTICAL_OFFSET_BUFFER
|
#define FB_IOCTL_GET_HEAD_VERTICAL_OFFSET_BUFFER FB_IOCTL_GET_HEAD_VERTICAL_OFFSET_BUFFER
|
||||||
#define FB_IOCTL_FLUSH_HEAD_BUFFERS FB_IOCTL_FLUSH_HEAD_BUFFERS
|
#define FB_IOCTL_FLUSH_HEAD_BUFFERS FB_IOCTL_FLUSH_HEAD_BUFFERS
|
||||||
#define FB_IOCTL_FLUSH_HEAD FB_IOCTL_FLUSH_HEAD
|
#define FB_IOCTL_FLUSH_HEAD FB_IOCTL_FLUSH_HEAD
|
||||||
|
#define FB_IOCTL_SET_HEAD_MODE_SETTING FB_IOCTL_SET_HEAD_MODE_SETTING
|
||||||
|
#define FB_IOCTL_GET_HEAD_MODE_SETTING FB_IOCTL_GET_HEAD_MODE_SETTING
|
||||||
|
#define FB_IOCTL_SET_SAFE_HEAD_MODE_SETTING FB_IOCTL_SET_SAFE_HEAD_MODE_SETTING
|
||||||
#define KEYBOARD_IOCTL_GET_NUM_LOCK KEYBOARD_IOCTL_GET_NUM_LOCK
|
#define KEYBOARD_IOCTL_GET_NUM_LOCK KEYBOARD_IOCTL_GET_NUM_LOCK
|
||||||
#define KEYBOARD_IOCTL_SET_NUM_LOCK KEYBOARD_IOCTL_SET_NUM_LOCK
|
#define KEYBOARD_IOCTL_SET_NUM_LOCK KEYBOARD_IOCTL_SET_NUM_LOCK
|
||||||
#define KEYBOARD_IOCTL_GET_CAPS_LOCK KEYBOARD_IOCTL_GET_CAPS_LOCK
|
#define KEYBOARD_IOCTL_GET_CAPS_LOCK KEYBOARD_IOCTL_GET_CAPS_LOCK
|
||||||
|
|
|
@ -721,6 +721,13 @@ void Compositor::flush(Screen& screen)
|
||||||
// now so that they can be sent to the device.
|
// now so that they can be sent to the device.
|
||||||
screen.flush_display(screen_data.m_buffers_are_flipped ? 1 : 0);
|
screen.flush_display(screen_data.m_buffers_are_flipped ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note: We write all contents from the internal buffer of WindowServer Screen
|
||||||
|
// to the actual framebuffer with the write() syscall, but after we flush the screen
|
||||||
|
// to ensure we are in a "clean state"...
|
||||||
|
// FIXME: This write is completely inefficient and needs to be done in chunks
|
||||||
|
// only when appropriate...
|
||||||
|
screen.write_all_display_contents();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Compositor::invalidate_screen()
|
void Compositor::invalidate_screen()
|
||||||
|
|
|
@ -17,8 +17,9 @@
|
||||||
|
|
||||||
namespace WindowServer {
|
namespace WindowServer {
|
||||||
|
|
||||||
HardwareScreenBackend::HardwareScreenBackend(String device)
|
HardwareScreenBackend::HardwareScreenBackend(String device, bool display_connector_device_backed)
|
||||||
: m_device(move(device))
|
: m_device(move(device))
|
||||||
|
, display_connector_device_backed(display_connector_device_backed)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +43,10 @@ HardwareScreenBackend::~HardwareScreenBackend()
|
||||||
m_framebuffer_fd = -1;
|
m_framebuffer_fd = -1;
|
||||||
}
|
}
|
||||||
if (m_framebuffer) {
|
if (m_framebuffer) {
|
||||||
MUST(Core::System::munmap(m_framebuffer, m_size_in_bytes));
|
if (!display_connector_device_backed)
|
||||||
|
MUST(Core::System::munmap(m_framebuffer, m_size_in_bytes));
|
||||||
|
else
|
||||||
|
free(m_framebuffer);
|
||||||
|
|
||||||
m_framebuffer = nullptr;
|
m_framebuffer = nullptr;
|
||||||
m_size_in_bytes = 0;
|
m_size_in_bytes = 0;
|
||||||
|
@ -51,41 +55,95 @@ HardwareScreenBackend::~HardwareScreenBackend()
|
||||||
|
|
||||||
ErrorOr<void> HardwareScreenBackend::set_head_resolution(FBHeadResolution resolution)
|
ErrorOr<void> HardwareScreenBackend::set_head_resolution(FBHeadResolution resolution)
|
||||||
{
|
{
|
||||||
auto rc = fb_set_resolution(m_framebuffer_fd, &resolution);
|
if (!display_connector_device_backed) {
|
||||||
if (rc != 0)
|
auto rc = fb_set_resolution(m_framebuffer_fd, &resolution);
|
||||||
return Error::from_syscall("fb_set_resolution", rc);
|
if (rc != 0)
|
||||||
|
return Error::from_syscall("fb_set_resolution", rc);
|
||||||
|
} else {
|
||||||
|
FBHeadModeSetting mode_setting;
|
||||||
|
memset(&mode_setting, 0, sizeof(FBHeadModeSetting));
|
||||||
|
mode_setting.horizontal_active = resolution.width;
|
||||||
|
mode_setting.vertical_active = resolution.height;
|
||||||
|
mode_setting.horizontal_stride = resolution.pitch;
|
||||||
|
auto rc = fb_set_head_mode_setting(m_framebuffer_fd, &mode_setting);
|
||||||
|
if (rc != 0)
|
||||||
|
return Error::from_syscall("fb_set_head_mode_setting", rc);
|
||||||
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<void> HardwareScreenBackend::unmap_framebuffer()
|
ErrorOr<void> HardwareScreenBackend::unmap_framebuffer()
|
||||||
{
|
{
|
||||||
if (m_framebuffer) {
|
if (m_framebuffer) {
|
||||||
size_t previous_size_in_bytes = m_size_in_bytes;
|
if (!display_connector_device_backed) {
|
||||||
return Core::System::munmap(m_framebuffer, previous_size_in_bytes);
|
size_t previous_size_in_bytes = m_size_in_bytes;
|
||||||
|
return Core::System::munmap(m_framebuffer, previous_size_in_bytes);
|
||||||
|
} else {
|
||||||
|
free(m_framebuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> HardwareScreenBackend::write_all_contents(Gfx::IntRect const& virtual_rect)
|
||||||
|
{
|
||||||
|
if (!display_connector_device_backed)
|
||||||
|
return {};
|
||||||
|
lseek(m_framebuffer_fd, 0, SEEK_SET);
|
||||||
|
write(m_framebuffer_fd, scanline(0, 0), virtual_rect.height() * m_pitch);
|
||||||
|
if (m_can_set_head_buffer) {
|
||||||
|
if (lseek(m_framebuffer_fd, virtual_rect.height() * m_pitch, SEEK_SET) < 0) {
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (write(m_framebuffer_fd, scanline(0, 0), virtual_rect.height() * m_pitch) < 0)
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<void> HardwareScreenBackend::map_framebuffer()
|
ErrorOr<void> HardwareScreenBackend::map_framebuffer()
|
||||||
{
|
{
|
||||||
FBHeadProperties properties;
|
if (!display_connector_device_backed) {
|
||||||
properties.head_index = 0;
|
FBHeadProperties properties;
|
||||||
int rc = fb_get_head_properties(m_framebuffer_fd, &properties);
|
properties.head_index = 0;
|
||||||
if (rc != 0)
|
int rc = fb_get_head_properties(m_framebuffer_fd, &properties);
|
||||||
return Error::from_syscall("fb_get_head_properties", rc);
|
if (rc != 0)
|
||||||
m_size_in_bytes = properties.buffer_length;
|
return Error::from_syscall("fb_get_head_properties", rc);
|
||||||
|
m_size_in_bytes = properties.buffer_length;
|
||||||
|
|
||||||
m_framebuffer = (Gfx::ARGB32*)TRY(Core::System::mmap(nullptr, m_size_in_bytes, PROT_READ | PROT_WRITE, MAP_SHARED, m_framebuffer_fd, 0));
|
m_framebuffer = (Gfx::ARGB32*)TRY(Core::System::mmap(nullptr, m_size_in_bytes, PROT_READ | PROT_WRITE, MAP_SHARED, m_framebuffer_fd, 0));
|
||||||
|
|
||||||
if (m_can_set_head_buffer) {
|
if (m_can_set_head_buffer) {
|
||||||
// Note: fall back to assuming the second buffer starts right after the last line of the first
|
// Note: fall back to assuming the second buffer starts right after the last line of the first
|
||||||
// Note: for now, this calculation works quite well, so need to defer it to another function
|
// Note: for now, this calculation works quite well, so need to defer it to another function
|
||||||
// that does ioctl to figure out the correct offset. If a Framebuffer device ever happens to
|
// that does ioctl to figure out the correct offset. If a Framebuffer device ever happens to
|
||||||
// to set the second buffer at different location than this, we might need to consider bringing
|
// to set the second buffer at different location than this, we might need to consider bringing
|
||||||
// back a function with ioctl to check this.
|
// back a function with ioctl to check this.
|
||||||
m_back_buffer_offset = static_cast<size_t>(properties.pitch) * properties.height;
|
m_back_buffer_offset = static_cast<size_t>(properties.pitch) * properties.height;
|
||||||
|
} else {
|
||||||
|
m_back_buffer_offset = 0;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
m_back_buffer_offset = 0;
|
FBHeadModeSetting mode_setting {};
|
||||||
|
memset(&mode_setting, 0, sizeof(FBHeadModeSetting));
|
||||||
|
int rc = fb_get_head_mode_setting(m_framebuffer_fd, &mode_setting);
|
||||||
|
if (rc != 0) {
|
||||||
|
return Error::from_syscall("fb_get_head_mode_setting", rc);
|
||||||
|
}
|
||||||
|
m_size_in_bytes = mode_setting.horizontal_stride * mode_setting.vertical_active * 2;
|
||||||
|
m_framebuffer = (Gfx::ARGB32*)malloc(m_size_in_bytes);
|
||||||
|
if (m_can_set_head_buffer) {
|
||||||
|
// Note: fall back to assuming the second buffer starts right after the last line of the first
|
||||||
|
// Note: for now, this calculation works quite well, so need to defer it to another function
|
||||||
|
// that does ioctl to figure out the correct offset. If a Framebuffer device ever happens to
|
||||||
|
// to set the second buffer at different location than this, we might need to consider bringing
|
||||||
|
// back a function with ioctl to check this.
|
||||||
|
m_back_buffer_offset = static_cast<size_t>(mode_setting.horizontal_stride) * mode_setting.vertical_active;
|
||||||
|
} else {
|
||||||
|
m_back_buffer_offset = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
|
@ -93,13 +151,34 @@ ErrorOr<void> HardwareScreenBackend::map_framebuffer()
|
||||||
|
|
||||||
ErrorOr<FBHeadProperties> HardwareScreenBackend::get_head_properties()
|
ErrorOr<FBHeadProperties> HardwareScreenBackend::get_head_properties()
|
||||||
{
|
{
|
||||||
FBHeadProperties properties;
|
if (!display_connector_device_backed) {
|
||||||
properties.head_index = 0;
|
FBHeadProperties properties;
|
||||||
int rc = fb_get_head_properties(m_framebuffer_fd, &properties);
|
properties.head_index = 0;
|
||||||
if (rc != 0)
|
int rc = fb_get_head_properties(m_framebuffer_fd, &properties);
|
||||||
return Error::from_syscall("fb_get_head_properties", rc);
|
if (rc != 0)
|
||||||
m_pitch = static_cast<int>(properties.pitch);
|
return Error::from_syscall("fb_get_head_properties", rc);
|
||||||
return properties;
|
m_pitch = static_cast<int>(properties.pitch);
|
||||||
|
return properties;
|
||||||
|
} else {
|
||||||
|
FBHeadModeSetting mode_setting {};
|
||||||
|
memset(&mode_setting, 0, sizeof(FBHeadModeSetting));
|
||||||
|
int rc = fb_get_head_mode_setting(m_framebuffer_fd, &mode_setting);
|
||||||
|
if (rc != 0) {
|
||||||
|
return Error::from_syscall("fb_get_head_mode_setting", rc);
|
||||||
|
}
|
||||||
|
m_pitch = mode_setting.horizontal_stride;
|
||||||
|
// Note: We translate (for now, until Framebuffer devices are removed) the FBHeadModeSetting
|
||||||
|
// structure to FBHeadProperties.
|
||||||
|
FBHeadProperties properties;
|
||||||
|
properties.head_index = 0;
|
||||||
|
properties.pitch = mode_setting.horizontal_stride;
|
||||||
|
properties.width = mode_setting.horizontal_active;
|
||||||
|
properties.height = mode_setting.vertical_active;
|
||||||
|
properties.offset = 0;
|
||||||
|
properties.buffer_length = mode_setting.horizontal_stride * mode_setting.vertical_active * 2;
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HardwareScreenBackend::set_head_buffer(int head_index)
|
void HardwareScreenBackend::set_head_buffer(int head_index)
|
||||||
|
|
|
@ -18,7 +18,7 @@ class HardwareScreenBackend : public ScreenBackend {
|
||||||
public:
|
public:
|
||||||
virtual ~HardwareScreenBackend();
|
virtual ~HardwareScreenBackend();
|
||||||
|
|
||||||
HardwareScreenBackend(String device);
|
HardwareScreenBackend(String device, bool display_connector_device_backed);
|
||||||
|
|
||||||
virtual ErrorOr<void> open() override;
|
virtual ErrorOr<void> open() override;
|
||||||
|
|
||||||
|
@ -32,8 +32,17 @@ public:
|
||||||
virtual ErrorOr<void> set_head_resolution(FBHeadResolution) override;
|
virtual ErrorOr<void> set_head_resolution(FBHeadResolution) override;
|
||||||
virtual ErrorOr<FBHeadProperties> get_head_properties() override;
|
virtual ErrorOr<FBHeadProperties> get_head_properties() override;
|
||||||
|
|
||||||
|
virtual ErrorOr<void> write_all_contents(Gfx::IntRect const&) override;
|
||||||
|
|
||||||
String m_device {};
|
String m_device {};
|
||||||
int m_framebuffer_fd { -1 };
|
int m_framebuffer_fd { -1 };
|
||||||
|
bool const display_connector_device_backed { false };
|
||||||
|
|
||||||
|
Gfx::ARGB32* scanline(int buffer_index, int y) const
|
||||||
|
{
|
||||||
|
size_t buffer_offset = buffer_index == 1 ? m_back_buffer_offset : 0;
|
||||||
|
return reinterpret_cast<Gfx::ARGB32*>(((u8*)m_framebuffer) + buffer_offset + (y * m_pitch));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -231,7 +231,7 @@ bool Screen::open_device()
|
||||||
|
|
||||||
switch (info.mode) {
|
switch (info.mode) {
|
||||||
case ScreenLayout::Screen::Mode::Device: {
|
case ScreenLayout::Screen::Mode::Device: {
|
||||||
m_backend = make<HardwareScreenBackend>(info.device.value());
|
m_backend = make<HardwareScreenBackend>(info.device.value(), false);
|
||||||
auto return_value = m_backend->open();
|
auto return_value = m_backend->open();
|
||||||
if (return_value.is_error()) {
|
if (return_value.is_error()) {
|
||||||
dbgln("Screen #{}: Failed to open backend: {}", index(), return_value.error());
|
dbgln("Screen #{}: Failed to open backend: {}", index(), return_value.error());
|
||||||
|
@ -241,6 +241,17 @@ bool Screen::open_device()
|
||||||
set_resolution(true);
|
set_resolution(true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
case ScreenLayout::Screen::Mode::DisplayConnectorDevice: {
|
||||||
|
m_backend = make<HardwareScreenBackend>(info.device.value(), true);
|
||||||
|
auto return_value = m_backend->open();
|
||||||
|
if (return_value.is_error()) {
|
||||||
|
dbgln("Screen #{}: Failed to open display connector backend: {}", index(), return_value.error());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_resolution(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
case ScreenLayout::Screen::Mode::Virtual: {
|
case ScreenLayout::Screen::Mode::Virtual: {
|
||||||
m_backend = make<VirtualScreenBackend>();
|
m_backend = make<VirtualScreenBackend>();
|
||||||
// Virtual device open should never fail.
|
// Virtual device open should never fail.
|
||||||
|
@ -539,6 +550,11 @@ void Screen::flush_display(int buffer_index)
|
||||||
flush_rects.pending_flush_rects.clear_with_capacity();
|
flush_rects.pending_flush_rects.clear_with_capacity();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Screen::write_all_display_contents()
|
||||||
|
{
|
||||||
|
MUST(m_backend->write_all_contents(m_virtual_rect));
|
||||||
|
}
|
||||||
|
|
||||||
void Screen::flush_display_front_buffer(int front_buffer_index, Gfx::IntRect& rect)
|
void Screen::flush_display_front_buffer(int front_buffer_index, Gfx::IntRect& rect)
|
||||||
{
|
{
|
||||||
VERIFY(m_backend->m_can_device_flush_buffers);
|
VERIFY(m_backend->m_can_device_flush_buffers);
|
||||||
|
|
|
@ -174,6 +174,8 @@ public:
|
||||||
|
|
||||||
CompositorScreenData& compositor_screen_data() { return *m_compositor_screen_data; }
|
CompositorScreenData& compositor_screen_data() { return *m_compositor_screen_data; }
|
||||||
|
|
||||||
|
void write_all_display_contents();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Screen(size_t);
|
Screen(size_t);
|
||||||
bool open_device();
|
bool open_device();
|
||||||
|
|
|
@ -34,6 +34,8 @@ public:
|
||||||
virtual ErrorOr<void> set_head_resolution(FBHeadResolution) = 0;
|
virtual ErrorOr<void> set_head_resolution(FBHeadResolution) = 0;
|
||||||
virtual ErrorOr<FBHeadProperties> get_head_properties() = 0;
|
virtual ErrorOr<FBHeadProperties> get_head_properties() = 0;
|
||||||
|
|
||||||
|
virtual ErrorOr<void> write_all_contents(Gfx::IntRect const&) { return {}; }
|
||||||
|
|
||||||
bool m_can_device_flush_buffers { true };
|
bool m_can_device_flush_buffers { true };
|
||||||
bool m_can_set_head_buffer { false };
|
bool m_can_set_head_buffer { false };
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ public:
|
||||||
enum class Mode {
|
enum class Mode {
|
||||||
Invalid,
|
Invalid,
|
||||||
Device,
|
Device,
|
||||||
|
DisplayConnectorDevice,
|
||||||
Virtual,
|
Virtual,
|
||||||
} mode;
|
} mode;
|
||||||
Optional<String> device;
|
Optional<String> device;
|
||||||
|
@ -42,6 +43,7 @@ public:
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
__ENUMERATE_MODE_ENUM(Invalid)
|
__ENUMERATE_MODE_ENUM(Invalid)
|
||||||
__ENUMERATE_MODE_ENUM(Device)
|
__ENUMERATE_MODE_ENUM(Device)
|
||||||
|
__ENUMERATE_MODE_ENUM(DisplayConnectorDevice)
|
||||||
__ENUMERATE_MODE_ENUM(Virtual)
|
__ENUMERATE_MODE_ENUM(Virtual)
|
||||||
}
|
}
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
|
@ -59,7 +61,9 @@ public:
|
||||||
bool normalize();
|
bool normalize();
|
||||||
bool load_config(Core::ConfigFile const& config_file, String* error_msg = nullptr);
|
bool load_config(Core::ConfigFile const& config_file, String* error_msg = nullptr);
|
||||||
bool save_config(Core::ConfigFile& config_file, bool sync = true) const;
|
bool save_config(Core::ConfigFile& config_file, bool sync = true) const;
|
||||||
|
// FIXME: Remove this once framebuffer devices are removed.
|
||||||
bool try_auto_add_framebuffer(String const&);
|
bool try_auto_add_framebuffer(String const&);
|
||||||
|
bool try_auto_add_display_connector(String const&);
|
||||||
|
|
||||||
// TODO: spaceship operator
|
// TODO: spaceship operator
|
||||||
bool operator!=(ScreenLayout const& other) const;
|
bool operator!=(ScreenLayout const& other) const;
|
||||||
|
|
|
@ -236,8 +236,15 @@ bool ScreenLayout::load_config(const Core::ConfigFile& config_file, String* erro
|
||||||
if (!config_file.has_group(group_name))
|
if (!config_file.has_group(group_name))
|
||||||
break;
|
break;
|
||||||
auto str_mode = config_file.read_entry(group_name, "Mode");
|
auto str_mode = config_file.read_entry(group_name, "Mode");
|
||||||
auto mode = str_mode == "Device" ? Screen::Mode::Device : str_mode == "Virtual" ? Screen::Mode::Virtual
|
Screen::Mode mode { Screen::Mode::Invalid };
|
||||||
: Screen::Mode::Invalid;
|
if (str_mode == "Device") {
|
||||||
|
mode = Screen::Mode::Device;
|
||||||
|
} else if (str_mode == "DisplayConnectorDevice") {
|
||||||
|
mode = Screen::Mode::DisplayConnectorDevice;
|
||||||
|
} else if (str_mode == "Virtual") {
|
||||||
|
mode = Screen::Mode::Virtual;
|
||||||
|
}
|
||||||
|
|
||||||
if (mode == Screen::Mode::Invalid) {
|
if (mode == Screen::Mode::Invalid) {
|
||||||
*error_msg = String::formatted("Invalid screen mode '{}'", str_mode);
|
*error_msg = String::formatted("Invalid screen mode '{}'", str_mode);
|
||||||
*this = {};
|
*this = {};
|
||||||
|
@ -302,6 +309,90 @@ bool ScreenLayout::operator!=(const ScreenLayout& other) const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ScreenLayout::try_auto_add_display_connector(String const& device_path)
|
||||||
|
{
|
||||||
|
int display_connector_fd = open(device_path.characters(), O_RDWR | O_CLOEXEC);
|
||||||
|
if (display_connector_fd < 0) {
|
||||||
|
int err = errno;
|
||||||
|
dbgln("Error ({}) opening display connector device {}", err, device_path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ScopeGuard fd_guard([&] {
|
||||||
|
close(display_connector_fd);
|
||||||
|
});
|
||||||
|
|
||||||
|
FBHeadModeSetting mode_setting {};
|
||||||
|
memset(&mode_setting, 0, sizeof(FBHeadModeSetting));
|
||||||
|
if (fb_get_head_mode_setting(display_connector_fd, &mode_setting) < 0) {
|
||||||
|
int err = errno;
|
||||||
|
dbgln("Error ({}) querying resolution from display connector device {}", err, device_path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (mode_setting.horizontal_active == 0 || mode_setting.vertical_active == 0) {
|
||||||
|
// Looks like the display is not turned on. Since we don't know what the desired
|
||||||
|
// resolution should be, use the main display as reference.
|
||||||
|
if (screens.is_empty())
|
||||||
|
return false;
|
||||||
|
auto& main_screen = screens[main_screen_index];
|
||||||
|
mode_setting.horizontal_active = main_screen.resolution.width();
|
||||||
|
mode_setting.vertical_active = main_screen.resolution.height();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto append_screen = [&](Gfx::IntRect const& new_screen_rect) {
|
||||||
|
screens.append({ .mode = Screen::Mode::DisplayConnectorDevice,
|
||||||
|
.device = device_path,
|
||||||
|
.location = new_screen_rect.location(),
|
||||||
|
.resolution = new_screen_rect.size(),
|
||||||
|
.scale_factor = 1 });
|
||||||
|
};
|
||||||
|
|
||||||
|
if (screens.is_empty()) {
|
||||||
|
append_screen({ 0, 0, mode_setting.horizontal_active, mode_setting.vertical_active });
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto original_screens = move(screens);
|
||||||
|
screens = original_screens;
|
||||||
|
ArmedScopeGuard screens_guard([&] {
|
||||||
|
screens = move(original_screens);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Now that we know the current resolution, try to find a location that we can add onto
|
||||||
|
// TODO: make this a little more sophisticated in case a more complex layout is already configured
|
||||||
|
for (auto& screen : screens) {
|
||||||
|
auto screen_rect = screen.virtual_rect();
|
||||||
|
Gfx::IntRect new_screen_rect {
|
||||||
|
screen_rect.right() + 1,
|
||||||
|
screen_rect.top(),
|
||||||
|
(int)mode_setting.horizontal_active,
|
||||||
|
(int)mode_setting.vertical_active
|
||||||
|
};
|
||||||
|
|
||||||
|
bool collision = false;
|
||||||
|
for (auto& other_screen : screens) {
|
||||||
|
if (&screen == &other_screen)
|
||||||
|
continue;
|
||||||
|
if (other_screen.virtual_rect().intersects(new_screen_rect)) {
|
||||||
|
collision = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!collision) {
|
||||||
|
append_screen(new_screen_rect);
|
||||||
|
if (is_valid()) {
|
||||||
|
// We got lucky!
|
||||||
|
screens_guard.disarm();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dbgln("Failed to add display connector device {} with resolution {}x{} to screen layout", device_path, mode_setting.horizontal_active, mode_setting.vertical_active);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: Remove this once framebuffer devices are removed.
|
||||||
bool ScreenLayout::try_auto_add_framebuffer(String const& device_path)
|
bool ScreenLayout::try_auto_add_framebuffer(String const& device_path)
|
||||||
{
|
{
|
||||||
int framebuffer_fd = open(device_path.characters(), O_RDWR | O_CLOEXEC);
|
int framebuffer_fd = open(device_path.characters(), O_RDWR | O_CLOEXEC);
|
||||||
|
|
|
@ -68,7 +68,8 @@ ErrorOr<int> serenity_main(Main::Arguments)
|
||||||
WindowServer::ScreenLayout screen_layout;
|
WindowServer::ScreenLayout screen_layout;
|
||||||
String error_msg;
|
String error_msg;
|
||||||
|
|
||||||
auto add_unconfigured_devices = [&]() {
|
// FIXME: Remove this once framebuffer devices are removed.
|
||||||
|
auto add_unconfigured_framebuffer_devices = [&]() {
|
||||||
// Enumerate the /dev/fbX devices and try to set up any ones we find that we haven't already used
|
// Enumerate the /dev/fbX devices and try to set up any ones we find that we haven't already used
|
||||||
Core::DirIterator di("/dev", Core::DirIterator::SkipParentAndBaseDir);
|
Core::DirIterator di("/dev", Core::DirIterator::SkipParentAndBaseDir);
|
||||||
while (di.has_next()) {
|
while (di.has_next()) {
|
||||||
|
@ -76,6 +77,7 @@ ErrorOr<int> serenity_main(Main::Arguments)
|
||||||
if (!path.starts_with("fb"))
|
if (!path.starts_with("fb"))
|
||||||
continue;
|
continue;
|
||||||
auto full_path = String::formatted("/dev/{}", path);
|
auto full_path = String::formatted("/dev/{}", path);
|
||||||
|
dbgln("{} :", full_path);
|
||||||
if (!Core::File::is_device(full_path))
|
if (!Core::File::is_device(full_path))
|
||||||
continue;
|
continue;
|
||||||
if (fb_devices_configured.find(full_path) != fb_devices_configured.end())
|
if (fb_devices_configured.find(full_path) != fb_devices_configured.end())
|
||||||
|
@ -85,10 +87,31 @@ ErrorOr<int> serenity_main(Main::Arguments)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
auto add_unconfigured_display_connector_devices = [&]() {
|
||||||
|
// Enumerate the /dev/fbX devices and try to set up any ones we find that we haven't already used
|
||||||
|
Core::DirIterator di("/dev/gpu", Core::DirIterator::SkipParentAndBaseDir);
|
||||||
|
while (di.has_next()) {
|
||||||
|
auto path = di.next_path();
|
||||||
|
if (!path.starts_with("connector"))
|
||||||
|
continue;
|
||||||
|
auto full_path = String::formatted("/dev/gpu/{}", path);
|
||||||
|
if (!Core::File::is_device(full_path))
|
||||||
|
continue;
|
||||||
|
if (fb_devices_configured.find(full_path) != fb_devices_configured.end())
|
||||||
|
continue;
|
||||||
|
if (!screen_layout.try_auto_add_display_connector(full_path))
|
||||||
|
dbgln("Could not auto-add framebuffer device {} to screen layout", full_path);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
auto apply_and_generate_generic_screen_layout = [&]() {
|
auto apply_and_generate_generic_screen_layout = [&]() {
|
||||||
screen_layout = {};
|
screen_layout = {};
|
||||||
fb_devices_configured = {};
|
fb_devices_configured = {};
|
||||||
add_unconfigured_devices();
|
|
||||||
|
// FIXME: Remove this once framebuffer devices are removed.
|
||||||
|
add_unconfigured_framebuffer_devices();
|
||||||
|
|
||||||
|
add_unconfigured_display_connector_devices();
|
||||||
if (!WindowServer::Screen::apply_layout(move(screen_layout), error_msg)) {
|
if (!WindowServer::Screen::apply_layout(move(screen_layout), error_msg)) {
|
||||||
dbgln("Failed to apply generated fallback screen layout: {}", error_msg);
|
dbgln("Failed to apply generated fallback screen layout: {}", error_msg);
|
||||||
return false;
|
return false;
|
||||||
|
@ -100,10 +123,13 @@ ErrorOr<int> serenity_main(Main::Arguments)
|
||||||
|
|
||||||
if (screen_layout.load_config(*wm_config, &error_msg)) {
|
if (screen_layout.load_config(*wm_config, &error_msg)) {
|
||||||
for (auto& screen_info : screen_layout.screens)
|
for (auto& screen_info : screen_layout.screens)
|
||||||
if (screen_info.mode == WindowServer::ScreenLayout::Screen::Mode::Device)
|
if (screen_info.mode == WindowServer::ScreenLayout::Screen::Mode::Device || screen_info.mode == WindowServer::ScreenLayout::Screen::Mode::DisplayConnectorDevice)
|
||||||
fb_devices_configured.set(screen_info.device.value());
|
fb_devices_configured.set(screen_info.device.value());
|
||||||
|
|
||||||
add_unconfigured_devices();
|
// FIXME: Remove this once framebuffer devices are removed.
|
||||||
|
add_unconfigured_framebuffer_devices();
|
||||||
|
|
||||||
|
add_unconfigured_display_connector_devices();
|
||||||
|
|
||||||
if (!WindowServer::Screen::apply_layout(move(screen_layout), error_msg)) {
|
if (!WindowServer::Screen::apply_layout(move(screen_layout), error_msg)) {
|
||||||
dbgln("Error applying screen layout: {}", error_msg);
|
dbgln("Error applying screen layout: {}", error_msg);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue