diff --git a/Kernel/API/FB.h b/Kernel/API/FB.h index 97cd287f4d..7c68f04634 100644 --- a/Kernel/API/FB.h +++ b/Kernel/API/FB.h @@ -28,6 +28,16 @@ ALWAYS_INLINE int fb_set_resolution(int fd, FBResolution* info) return ioctl(fd, FB_IOCTL_SET_RESOLUTION, info); } +ALWAYS_INLINE int fb_get_buffer_offset(int fd, int index, unsigned* offset) +{ + FBBufferOffset fb_buffer_offset; + fb_buffer_offset.buffer_index = index; + int result = ioctl(fd, FB_IOCTL_GET_BUFFER_OFFSET, &fb_buffer_offset); + if (result == 0) + *offset = fb_buffer_offset.offset; + return result; +} + ALWAYS_INLINE int fb_get_buffer(int fd, int* index) { return ioctl(fd, FB_IOCTL_GET_BUFFER, index); diff --git a/Userland/Libraries/LibC/sys/ioctl_numbers.h b/Userland/Libraries/LibC/sys/ioctl_numbers.h index c22f884ff6..62f0b2010e 100644 --- a/Userland/Libraries/LibC/sys/ioctl_numbers.h +++ b/Userland/Libraries/LibC/sys/ioctl_numbers.h @@ -30,6 +30,11 @@ struct FBRect { unsigned height; }; +struct FBBufferOffset { + int buffer_index; + unsigned offset; +}; + struct FBFlushRects { int buffer_index; unsigned count; @@ -55,6 +60,7 @@ enum IOCtlNumber { FB_IOCTL_GET_RESOLUTION, FB_IOCTL_SET_RESOLUTION, FB_IOCTL_GET_BUFFER, + FB_IOCTL_GET_BUFFER_OFFSET, FB_IOCTL_SET_BUFFER, FB_IOCTL_FLUSH_BUFFERS, SIOCSIFADDR, @@ -88,6 +94,7 @@ enum IOCtlNumber { #define FB_IOCTL_GET_RESOLUTION FB_IOCTL_GET_RESOLUTION #define FB_IOCTL_SET_RESOLUTION FB_IOCTL_SET_RESOLUTION #define FB_IOCTL_GET_BUFFER FB_IOCTL_GET_BUFFER +#define FB_IOCTL_GET_BUFFER_OFFSET FB_IOCTL_GET_BUFFER_OFFSET #define FB_IOCTL_SET_BUFFER FB_IOCTL_SET_BUFFER #define FB_IOCTL_FLUSH_BUFFERS FB_IOCTL_FLUSH_BUFFERS #define SIOCSIFADDR SIOCSIFADDR diff --git a/Userland/Services/WindowServer/Compositor.cpp b/Userland/Services/WindowServer/Compositor.cpp index c77373998e..dfc957dee1 100644 --- a/Userland/Services/WindowServer/Compositor.cpp +++ b/Userland/Services/WindowServer/Compositor.cpp @@ -87,12 +87,12 @@ void Compositor::ScreenData::init_bitmaps(Compositor& compositor, Screen& screen auto size = screen.size(); - m_front_bitmap = Gfx::Bitmap::create_wrapper(Gfx::BitmapFormat::BGRx8888, size, screen.scale_factor(), screen.pitch(), screen.scanline(0)); + m_front_bitmap = Gfx::Bitmap::create_wrapper(Gfx::BitmapFormat::BGRx8888, size, screen.scale_factor(), screen.pitch(), screen.scanline(0, 0)); m_front_painter = make(*m_front_bitmap); m_front_painter->translate(-screen.rect().location()); if (m_screen_can_set_buffer) - m_back_bitmap = Gfx::Bitmap::create_wrapper(Gfx::BitmapFormat::BGRx8888, size, screen.scale_factor(), screen.pitch(), screen.scanline(screen.physical_height())); + m_back_bitmap = Gfx::Bitmap::create_wrapper(Gfx::BitmapFormat::BGRx8888, size, screen.scale_factor(), screen.pitch(), screen.scanline(1, 0)); else m_back_bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::BGRx8888, size, screen.scale_factor()); m_back_painter = make(*m_back_bitmap); diff --git a/Userland/Services/WindowServer/Screen.cpp b/Userland/Services/WindowServer/Screen.cpp index 0214717e1a..12703f8889 100644 --- a/Userland/Services/WindowServer/Screen.cpp +++ b/Userland/Services/WindowServer/Screen.cpp @@ -225,6 +225,19 @@ bool Screen::set_resolution(bool initial) m_framebuffer = (Gfx::RGBA32*)mmap(nullptr, m_size_in_bytes, PROT_READ | PROT_WRITE, MAP_SHARED, m_framebuffer_fd, 0); VERIFY(m_framebuffer && m_framebuffer != (void*)-1); + + if (m_can_set_buffer) { + unsigned buffer_offset = 0; + rc = fb_get_buffer_offset(m_framebuffer_fd, 1, &buffer_offset); + if (rc == 0) { + m_back_buffer_offset = buffer_offset; + } else { + // fall back to assuming the second buffer starts right after the last line of the first + m_back_buffer_offset = physical_resolution.pitch * physical_resolution.height; + } + } else { + m_back_buffer_offset = 0; + } } m_info.resolution = { physical_resolution.width, physical_resolution.height }; @@ -255,6 +268,15 @@ void Screen::set_buffer(int index) VERIFY(rc == 0); } +size_t Screen::buffer_offset(int index) const +{ + if (index == 0) + return 0; + if (index == 1) + return m_back_buffer_offset; + VERIFY_NOT_REACHED(); +} + void ScreenInput::set_acceleration_factor(double factor) { VERIFY(factor >= mouse_accel_min && factor <= mouse_accel_max); diff --git a/Userland/Services/WindowServer/Screen.h b/Userland/Services/WindowServer/Screen.h index 4233cc78f1..159e830584 100644 --- a/Userland/Services/WindowServer/Screen.h +++ b/Userland/Services/WindowServer/Screen.h @@ -147,6 +147,7 @@ public: bool can_set_buffer() { return m_can_set_buffer; } void set_buffer(int index); + size_t buffer_offset(int index) const; int physical_width() const { return width() * scale_factor(); } int physical_height() const { return height() * scale_factor(); } @@ -156,7 +157,7 @@ public: int height() const { return m_virtual_rect.height(); } int scale_factor() const { return m_info.scale_factor; } - Gfx::RGBA32* scanline(int y); + Gfx::RGBA32* scanline(int buffer_index, int y); Gfx::IntSize physical_size() const { return { physical_width(), physical_height() }; } @@ -190,7 +191,8 @@ private: static Vector s_scale_factors_in_use; size_t m_index { 0 }; - size_t m_size_in_bytes; + size_t m_size_in_bytes { 0 }; + size_t m_back_buffer_offset { 0 }; Gfx::RGBA32* m_framebuffer { nullptr }; bool m_can_set_buffer { false }; @@ -204,9 +206,9 @@ private: ScreenLayout::Screen& m_info; }; -inline Gfx::RGBA32* Screen::scanline(int y) +inline Gfx::RGBA32* Screen::scanline(int buffer_index, int y) { - return reinterpret_cast(((u8*)m_framebuffer) + (y * m_pitch)); + return reinterpret_cast(((u8*)m_framebuffer) + buffer_offset(buffer_index) + (y * m_pitch)); } }