WindowServer: Coordinate double-buffering with the BochsVGA card.
Use the BochsVGA card's virtual-height + virtual-y features to implement a "hardware double buffering" type scheme. This is a performance degradation since we now draw a bunch more than before. But there's also no tearing or cursor flickering. I'm gonna commit this and try to improve upon it. :^)
This commit is contained in:
parent
1f159eaab0
commit
443d1c2237
Notes:
sideshowbarker
2024-07-19 15:50:37 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/443d1c2237d
6 changed files with 52 additions and 15 deletions
|
@ -13,6 +13,8 @@
|
|||
#define VBE_DISPI_INDEX_BANK 0x5
|
||||
#define VBE_DISPI_INDEX_VIRT_WIDTH 0x6
|
||||
#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7
|
||||
#define VBE_DISPI_INDEX_X_OFFSET 0x8
|
||||
#define VBE_DISPI_INDEX_Y_OFFSET 0x9
|
||||
#define VBE_DISPI_DISABLED 0x00
|
||||
#define VBE_DISPI_ENABLED 0x01
|
||||
#define VBE_DISPI_LFB_ENABLED 0x40
|
||||
|
@ -42,12 +44,17 @@ void BochsVGADevice::set_resolution(int width, int height)
|
|||
set_register(VBE_DISPI_INDEX_XRES, width);
|
||||
set_register(VBE_DISPI_INDEX_YRES, height);
|
||||
set_register(VBE_DISPI_INDEX_VIRT_WIDTH, width);
|
||||
set_register(VBE_DISPI_INDEX_VIRT_HEIGHT, height);
|
||||
set_register(VBE_DISPI_INDEX_VIRT_HEIGHT, height * 2);
|
||||
set_register(VBE_DISPI_INDEX_BPP, 32);
|
||||
set_register(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);
|
||||
set_register(VBE_DISPI_INDEX_BANK, 0);
|
||||
}
|
||||
|
||||
void BochsVGADevice::set_y_offset(int offset)
|
||||
{
|
||||
set_register(VBE_DISPI_INDEX_Y_OFFSET, offset);
|
||||
}
|
||||
|
||||
dword BochsVGADevice::find_framebuffer_address()
|
||||
{
|
||||
static const PCI::ID bochs_vga_id = { 0x1234, 0x1111 };
|
||||
|
|
|
@ -15,6 +15,7 @@ public:
|
|||
|
||||
PhysicalAddress framebuffer_address() const { return m_framebuffer_address; }
|
||||
void set_resolution(int width, int height);
|
||||
void set_y_offset(int);
|
||||
|
||||
private:
|
||||
void set_register(word index, word value);
|
||||
|
|
|
@ -276,7 +276,7 @@ DisplayInfo Process::set_video_resolution(int width, int height)
|
|||
info.height = height;
|
||||
info.bpp = 32;
|
||||
info.pitch = width * 4;
|
||||
size_t framebuffer_size = width * height * 4;
|
||||
size_t framebuffer_size = width * height * 4 * 2;
|
||||
if (!m_display_framebuffer_region) {
|
||||
auto framebuffer_vmo = VMObject::create_framebuffer_wrapper(BochsVGADevice::the().framebuffer_address(), framebuffer_size);
|
||||
m_display_framebuffer_region = allocate_region_with_vmo(LinearAddress(0xe0000000), framebuffer_size, move(framebuffer_vmo), 0, "framebuffer", true, true);
|
||||
|
|
|
@ -59,7 +59,7 @@ void WSScreen::on_receive_mouse_data(int dx, int dy, bool left_button, bool righ
|
|||
WSMessageLoop::the().post_message(&WSWindowManager::the(), move(message));
|
||||
}
|
||||
if (m_cursor_location != prev_location || prev_left_button != left_button)
|
||||
WSWindowManager::the().draw_cursor();
|
||||
WSWindowManager::the().invalidate_cursor();
|
||||
}
|
||||
|
||||
void WSScreen::on_receive_keyboard_data(Keyboard::Event kernel_event)
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <SharedGraphics/Painter.h>
|
||||
#include <SharedGraphics/CharacterBitmap.h>
|
||||
#include <AK/StdLibExtras.h>
|
||||
#include <Kernel/BochsVGADevice.h>
|
||||
|
||||
//#define DEBUG_COUNTERS
|
||||
//#define DEBUG_WID_IN_TITLE_BAR
|
||||
|
@ -115,6 +116,17 @@ static const char* cursor_bitmap_outer_ascii = {
|
|||
" ## "
|
||||
};
|
||||
|
||||
void WSWindowManager::flip_buffers()
|
||||
{
|
||||
swap(m_front_bitmap, m_back_bitmap);
|
||||
swap(m_front_painter, m_back_painter);
|
||||
if (m_buffers_are_flipped)
|
||||
BochsVGADevice::the().set_y_offset(0);
|
||||
else
|
||||
BochsVGADevice::the().set_y_offset(m_screen_rect.height());
|
||||
m_buffers_are_flipped = !m_buffers_are_flipped;
|
||||
}
|
||||
|
||||
WSWindowManager::WSWindowManager()
|
||||
: m_screen(WSScreen::the())
|
||||
, m_screen_rect(m_screen.rect())
|
||||
|
@ -125,8 +137,7 @@ WSWindowManager::WSWindowManager()
|
|||
#endif
|
||||
auto size = m_screen_rect.size();
|
||||
m_front_bitmap = GraphicsBitmap::create_wrapper(size, m_screen.scanline(0));
|
||||
auto* region = current->allocate_region(LinearAddress(), size.width() * size.height() * sizeof(RGBA32), "BackBitmap", true, true, true);
|
||||
m_back_bitmap = GraphicsBitmap::create_wrapper(m_screen_rect.size(), (RGBA32*)region->laddr().get());
|
||||
m_back_bitmap = GraphicsBitmap::create_wrapper(size, m_screen.scanline(size.height()));
|
||||
|
||||
m_front_painter = make<Painter>(*m_front_bitmap);
|
||||
m_back_painter = make<Painter>(*m_back_bitmap);
|
||||
|
@ -389,6 +400,9 @@ void WSWindowManager::compose()
|
|||
{
|
||||
LOCKER(m_lock);
|
||||
auto dirty_rects = move(m_dirty_rects);
|
||||
auto cursor_location = m_screen.cursor_location();
|
||||
dirty_rects.append(m_last_cursor_rect);
|
||||
dirty_rects.append({ cursor_location.x(), cursor_location.y(), (int)m_cursor_bitmap_inner->width(), (int)m_cursor_bitmap_inner->height() });
|
||||
#ifdef DEBUG_COUNTERS
|
||||
dbgprintf("[WM] compose #%u (%u rects)\n", ++m_compose_count, dirty_rects.size());
|
||||
dbgprintf("kmalloc stats: alloc:%u free:%u eternal:%u\n", sum_alloc, sum_free, kmalloc_sum_eternal);
|
||||
|
@ -440,9 +454,24 @@ void WSWindowManager::compose()
|
|||
}
|
||||
m_back_painter->clear_clip_rect();
|
||||
}
|
||||
draw_cursor();
|
||||
|
||||
if (m_flash_flush) {
|
||||
for (auto& rect : dirty_rects)
|
||||
m_front_painter->fill_rect(rect, Color::Yellow);
|
||||
}
|
||||
|
||||
flip_buffers();
|
||||
for (auto& r : dirty_rects)
|
||||
flush(r);
|
||||
draw_cursor();
|
||||
}
|
||||
|
||||
void WSWindowManager::invalidate_cursor()
|
||||
{
|
||||
LOCKER(m_lock);
|
||||
auto cursor_location = m_screen.cursor_location();
|
||||
Rect cursor_rect { cursor_location.x(), cursor_location.y(), (int)m_cursor_bitmap_inner->width(), (int)m_cursor_bitmap_inner->height() };
|
||||
invalidate(cursor_rect);
|
||||
}
|
||||
|
||||
void WSWindowManager::draw_cursor()
|
||||
|
@ -451,13 +480,12 @@ void WSWindowManager::draw_cursor()
|
|||
LOCKER(m_lock);
|
||||
auto cursor_location = m_screen.cursor_location();
|
||||
Rect cursor_rect { cursor_location.x(), cursor_location.y(), (int)m_cursor_bitmap_inner->width(), (int)m_cursor_bitmap_inner->height() };
|
||||
flush(m_last_cursor_rect.united(cursor_rect));
|
||||
Color inner_color = Color::White;
|
||||
Color outer_color = Color::Black;
|
||||
if (m_screen.left_mouse_button_pressed())
|
||||
swap(inner_color, outer_color);
|
||||
m_front_painter->draw_bitmap(cursor_location, *m_cursor_bitmap_inner, inner_color);
|
||||
m_front_painter->draw_bitmap(cursor_location, *m_cursor_bitmap_outer, outer_color);
|
||||
m_back_painter->draw_bitmap(cursor_location, *m_cursor_bitmap_inner, inner_color);
|
||||
m_back_painter->draw_bitmap(cursor_location, *m_cursor_bitmap_outer, outer_color);
|
||||
m_last_cursor_rect = cursor_rect;
|
||||
}
|
||||
|
||||
|
@ -565,15 +593,12 @@ void WSWindowManager::flush(const Rect& a_rect)
|
|||
#endif
|
||||
|
||||
RGBA32* front_ptr = m_front_bitmap->scanline(rect.y()) + rect.x();
|
||||
const RGBA32* back_ptr = m_back_bitmap->scanline(rect.y()) + rect.x();
|
||||
RGBA32* back_ptr = m_back_bitmap->scanline(rect.y()) + rect.x();
|
||||
size_t pitch = m_back_bitmap->pitch();
|
||||
|
||||
if (m_flash_flush)
|
||||
m_front_painter->fill_rect(rect, Color::Yellow);
|
||||
|
||||
for (int y = 0; y < rect.height(); ++y) {
|
||||
fast_dword_copy(front_ptr, back_ptr, rect.width());
|
||||
fast_dword_copy(back_ptr, front_ptr, rect.width());
|
||||
front_ptr = (RGBA32*)((byte*)front_ptr + pitch);
|
||||
back_ptr = (const RGBA32*)((const byte*)back_ptr + pitch);
|
||||
back_ptr = (RGBA32*)((byte*)back_ptr + pitch);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <AK/InlineLinkedList.h>
|
||||
#include <AK/WeakPtr.h>
|
||||
#include <AK/Lock.h>
|
||||
#include <AK/CircularQueue.h>
|
||||
#include "WSMessageReceiver.h"
|
||||
|
||||
class WSScreen;
|
||||
|
@ -29,6 +30,7 @@ public:
|
|||
|
||||
void move_to_front(WSWindow&);
|
||||
|
||||
void invalidate_cursor();
|
||||
void draw_cursor();
|
||||
|
||||
void invalidate(const WSWindow&);
|
||||
|
@ -54,6 +56,7 @@ private:
|
|||
|
||||
void compose();
|
||||
void paint_window_frame(WSWindow&);
|
||||
void flip_buffers();
|
||||
|
||||
WSScreen& m_screen;
|
||||
Rect m_screen_rect;
|
||||
|
@ -105,4 +108,5 @@ private:
|
|||
mutable Lock m_lock;
|
||||
|
||||
bool m_flash_flush { false };
|
||||
bool m_buffers_are_flipped { false };
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue