WindowServer: Detect framebuffer capabilities and settings

The main changes are twofold:

* Buffer flipping is now controlled by the m_screen_can_set_buffer flag
  in WSCompositor. This flag, in turn, is impacted by m_can_set_buffer
  flag, in WSScreen. m_can_set_buffer is set in the WSScreen constructor
  by checking the return value of fb_set_buffer. If the framebuffer
  supports this operation, it will succeed, and we record this fact. This
  information is then used by WSCompositor to set its own
  m_screen_can_set_buffer flag.

* WSScreen now only requests a resolution change of the framebuffer. The
  driver itself is ultimately responsible for what resolution or mode is
  actually set, so WSScreen has to read the response from that request,
  and has no choice but to accept the answer. This allows the driver to
  choose a "close enough" value to what was requested, or simply ignore
  it.

The result of this is that there is no special configuration necessary
for WindowServer to work with reduced-capability framebuffer devices.
This commit is contained in:
Conrad Pankoff 2019-08-18 14:32:14 +10:00 committed by Andreas Kling
parent 3932dfbb04
commit 23b6ef29dd
Notes: sideshowbarker 2024-07-19 12:37:37 +09:00
4 changed files with 68 additions and 51 deletions

View File

@ -31,16 +31,9 @@ WallpaperMode mode_to_enum(const String& name)
WSCompositor::WSCompositor()
{
auto size = WSScreen::the().size();
m_front_bitmap = GraphicsBitmap::create_wrapper(GraphicsBitmap::Format::RGB32, size, WSScreen::the().scanline(0));
m_screen_can_set_buffer = WSScreen::the().can_set_buffer();
if (can_flip_buffers())
m_back_bitmap = GraphicsBitmap::create_wrapper(GraphicsBitmap::Format::RGB32, size, WSScreen::the().scanline(size.height()));
else
m_back_bitmap = GraphicsBitmap::create(GraphicsBitmap::Format::RGB32, size);
m_front_painter = make<Painter>(*m_front_bitmap);
m_back_painter = make<Painter>(*m_back_bitmap);
init_bitmaps();
m_wallpaper_path = "/res/wallpapers/retro.rgb";
m_wallpaper = GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, m_wallpaper_path, { 1024, 768 });
@ -63,6 +56,25 @@ WSCompositor::WSCompositor()
m_immediate_compose_timer.set_interval(0);
}
void WSCompositor::init_bitmaps()
{
auto size = WSScreen::the().size();
m_front_bitmap = GraphicsBitmap::create_wrapper(GraphicsBitmap::Format::RGB32, size, WSScreen::the().scanline(0));
if (m_screen_can_set_buffer)
m_back_bitmap = GraphicsBitmap::create_wrapper(GraphicsBitmap::Format::RGB32, size, WSScreen::the().scanline(size.height()));
else
m_back_bitmap = GraphicsBitmap::create(GraphicsBitmap::Format::RGB32, size);
m_front_painter = make<Painter>(*m_front_bitmap);
m_back_painter = make<Painter>(*m_back_bitmap);
m_buffers_are_flipped = false;
invalidate();
}
void WSCompositor::compose()
{
auto& wm = WSWindowManager::the();
@ -172,7 +184,7 @@ void WSCompositor::compose()
m_front_painter->fill_rect(rect, Color::Yellow);
}
if (can_flip_buffers())
if (m_screen_can_set_buffer)
flip_buffers();
for (auto& r : dirty_rects.rects())
@ -203,7 +215,7 @@ void WSCompositor::flush(const Rect& a_rect)
RGBA32* to_ptr;
const RGBA32* from_ptr;
if (can_flip_buffers()) {
if (m_screen_can_set_buffer) {
to_ptr = back_ptr;
from_ptr = front_ptr;
} else {
@ -289,28 +301,22 @@ void WSCompositor::finish_setting_wallpaper(const String& path, NonnullRefPtr<Gr
void WSCompositor::flip_buffers()
{
ASSERT(can_flip_buffers());
ASSERT(m_screen_can_set_buffer);
swap(m_front_bitmap, m_back_bitmap);
swap(m_front_painter, m_back_painter);
int new_y_offset = m_buffers_are_flipped ? 0 : WSScreen::the().height();
WSScreen::the().set_y_offset(new_y_offset);
WSScreen::the().set_buffer(m_buffers_are_flipped ? 0 : 1);
m_buffers_are_flipped = !m_buffers_are_flipped;
}
void WSCompositor::set_resolution(int width, int height)
void WSCompositor::set_resolution(int desired_width, int desired_height)
{
auto screen_rect = WSScreen::the().rect();
if (screen_rect.width() == width && screen_rect.height() == height)
if (screen_rect.width() == desired_width && screen_rect.height() == desired_height)
return;
m_wallpaper_path = {};
m_wallpaper = nullptr;
WSScreen::the().set_resolution(width, height);
m_front_bitmap = GraphicsBitmap::create_wrapper(GraphicsBitmap::Format::RGB32, { width, height }, WSScreen::the().scanline(0));
m_back_bitmap = GraphicsBitmap::create_wrapper(GraphicsBitmap::Format::RGB32, { width, height }, WSScreen::the().scanline(height));
m_front_painter = make<Painter>(*m_front_bitmap);
m_back_painter = make<Painter>(*m_back_bitmap);
m_buffers_are_flipped = false;
invalidate();
WSScreen::the().set_resolution(desired_width, desired_height);
init_bitmaps();
compose();
}

View File

@ -27,7 +27,7 @@ public:
void invalidate();
void invalidate(const Rect&);
void set_resolution(int width, int height);
void set_resolution(int desired_width, int desired_height);
bool set_wallpaper(const String& path, Function<void(bool)>&& callback);
String wallpaper_path() const { return m_wallpaper_path; }
@ -35,10 +35,9 @@ public:
void invalidate_cursor();
Rect current_cursor_rect() const;
bool can_flip_buffers() const { return false; }
private:
WSCompositor();
void init_bitmaps();
void flip_buffers();
void flush(const Rect&);
void draw_cursor();
@ -52,6 +51,7 @@ private:
CTimer m_immediate_compose_timer;
bool m_flash_flush { false };
bool m_buffers_are_flipped { false };
bool m_screen_can_set_buffer { false };
RefPtr<GraphicsBitmap> m_front_bitmap;
RefPtr<GraphicsBitmap> m_back_bitmap;

View File

@ -3,8 +3,8 @@
#include "WSEvent.h"
#include "WSEventLoop.h"
#include "WSWindowManager.h"
#include <Kernel/FB.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <unistd.h>
@ -16,9 +16,7 @@ WSScreen& WSScreen::the()
return *s_the;
}
WSScreen::WSScreen(unsigned width, unsigned height)
: m_width(width)
, m_height(height)
WSScreen::WSScreen(unsigned desired_width, unsigned desired_height)
{
ASSERT(!s_the);
s_the = this;
@ -26,7 +24,11 @@ WSScreen::WSScreen(unsigned width, unsigned height)
m_framebuffer_fd = open("/dev/fb0", O_RDWR);
ASSERT(m_framebuffer_fd >= 0);
set_resolution(width, height);
if (fb_set_buffer(m_framebuffer_fd, 0) == 0) {
m_can_set_buffer = true;
}
set_resolution(desired_width, desired_height);
}
WSScreen::~WSScreen()
@ -35,30 +37,40 @@ WSScreen::~WSScreen()
void WSScreen::set_resolution(int width, int height)
{
struct BXVGAResolution {
int width;
int height;
};
BXVGAResolution resolution { (int)width, (int)height };
int rc = ioctl(m_framebuffer_fd, 1985, (int)&resolution);
FBResolution resolution { 0, (int)width, (int)height };
int rc = fb_set_resolution(m_framebuffer_fd, &resolution);
ASSERT(rc == 0);
on_change_resolution(resolution.pitch, resolution.width, resolution.height);
}
void WSScreen::on_change_resolution(int pitch, int width, int height)
{
if (m_framebuffer) {
size_t previous_size_in_bytes = m_width * m_height * sizeof(RGBA32) * 2;
size_t previous_size_in_bytes = m_size_in_bytes;
int rc = munmap(m_framebuffer, previous_size_in_bytes);
ASSERT(rc == 0);
}
size_t framebuffer_size_in_bytes = width * height * sizeof(RGBA32) * 2;
m_framebuffer = (RGBA32*)mmap(nullptr, framebuffer_size_in_bytes, PROT_READ | PROT_WRITE, MAP_SHARED, m_framebuffer_fd, 0);
int rc = fb_get_size_in_bytes(m_framebuffer_fd, &m_size_in_bytes);
ASSERT(rc == 0);
m_framebuffer = (RGBA32*)mmap(nullptr, m_size_in_bytes, PROT_READ | PROT_WRITE, MAP_SHARED, m_framebuffer_fd, 0);
ASSERT(m_framebuffer && m_framebuffer != (void*)-1);
m_pitch = pitch;
m_width = width;
m_height = height;
m_cursor_location.constrain(rect());
}
void WSScreen::set_buffer(int index)
{
ASSERT(m_can_set_buffer);
int rc = fb_set_buffer(m_framebuffer_fd, index);
ASSERT(rc == 0);
}
void WSScreen::on_receive_mouse_data(int dx, int dy, int dz, unsigned buttons)
{
auto prev_location = m_cursor_location;
@ -96,9 +108,3 @@ void WSScreen::on_receive_keyboard_data(KeyEvent kernel_event)
auto message = make<WSKeyEvent>(kernel_event.is_press() ? WSEvent::KeyDown : WSEvent::KeyUp, kernel_event.key, kernel_event.character, kernel_event.modifiers());
CEventLoop::current().post_event(WSWindowManager::the(), move(message));
}
void WSScreen::set_y_offset(int offset)
{
int rc = ioctl(m_framebuffer_fd, 1982, offset);
ASSERT(rc == 0);
}

View File

@ -11,6 +11,8 @@ public:
~WSScreen();
void set_resolution(int width, int height);
bool can_set_buffer() { return m_can_set_buffer; }
void set_buffer(int index);
int width() const { return m_width; }
int height() const { return m_height; }
@ -21,8 +23,6 @@ public:
Size size() const { return { width(), height() }; }
Rect rect() const { return { 0, 0, width(), height() }; }
void set_y_offset(int);
Point cursor_location() const { return m_cursor_location; }
unsigned mouse_button_state() const { return m_mouse_button_state; }
@ -30,8 +30,14 @@ public:
void on_receive_keyboard_data(KeyEvent);
private:
RGBA32* m_framebuffer { nullptr };
void on_change_resolution(int pitch, int width, int height);
size_t m_size_in_bytes;
RGBA32* m_framebuffer { nullptr };
bool m_can_set_buffer { false };
int m_pitch { 0 };
int m_width { 0 };
int m_height { 0 };
int m_framebuffer_fd { -1 };
@ -43,6 +49,5 @@ private:
inline RGBA32* WSScreen::scanline(int y)
{
size_t pitch = sizeof(RGBA32) * width();
return reinterpret_cast<RGBA32*>(((u8*)m_framebuffer) + (y * pitch));
return reinterpret_cast<RGBA32*>(((u8*)m_framebuffer) + (y * m_pitch));
}