Implement frame buffer double-buffering

This slowed down drawing to video in QEMU/VirtualBox but greatly sped up
doing so on real hardware (no longer reading from video memory).
Despite the speed-up, it is still quite slow though.
This commit is contained in:
Josh Holtrop 2022-11-08 06:19:03 -05:00
parent 55604468c8
commit edba40b2c6
3 changed files with 49 additions and 19 deletions

View File

@ -13,8 +13,11 @@ import hulk.kfont;
*/ */
struct fb struct fb
{ {
/** Frame buffer base address. */ /** Device frame buffer base address. */
private __gshared static uint * m_buffer; private __gshared static uint * m_device_buffer;
/** Frame buffer 1 base address. */
private __gshared static uint * m_buffer1;
/** Frame buffer width. */ /** Frame buffer width. */
private __gshared static uint m_width; private __gshared static uint m_width;
@ -47,14 +50,16 @@ struct fb
/** /**
* Initialize a frame buffer. * Initialize a frame buffer.
* *
* @param buffer Frame buffer base address. * @param device_buffer Device frame buffer base address.
* @param buffer1 Frame buffer 1 base address.
* @param width Frame buffer width. * @param width Frame buffer width.
* @param height Frame buffer height. * @param height Frame buffer height.
* @param stride Frame buffer stride. * @param stride Frame buffer stride.
*/ */
static void initialize(uint * buffer, uint width, uint height, uint stride) static void initialize(uint * device_buffer, uint * buffer1, uint width, uint height, uint stride)
{ {
m_buffer = buffer; m_device_buffer = device_buffer;
m_buffer1 = buffer1;
m_width = width; m_width = width;
m_height = height; m_height = height;
m_stride = stride; m_stride = stride;
@ -68,7 +73,8 @@ struct fb
*/ */
static void clear(uint color = 0u) static void clear(uint color = 0u)
{ {
memset32(m_buffer, color, m_buffer_size); memset32(m_buffer1, color, m_buffer_size);
memset32(m_device_buffer, color, m_buffer_size);
} }
/** /**
@ -85,7 +91,8 @@ struct fb
for (size_t iy = 0u; iy < height; iy++) for (size_t iy = 0u; iy < height; iy++)
{ {
size_t buffer_index = buffer_index(x, y); size_t buffer_index = buffer_index(x, y);
memset32(&m_buffer[buffer_index], color, width); memset32(&m_buffer1[buffer_index], color, width);
memset32(&m_device_buffer[buffer_index], color, width);
y++; y++;
} }
} }
@ -101,7 +108,8 @@ struct fb
static void hline(size_t x, size_t y, size_t width, uint color) static void hline(size_t x, size_t y, size_t width, uint color)
{ {
size_t buffer_index = buffer_index(x, y); size_t buffer_index = buffer_index(x, y);
memset32(&m_buffer[buffer_index], color, width); memset32(&m_buffer1[buffer_index], color, width);
memset32(&m_device_buffer[buffer_index], color, width);
} }
/** /**
@ -117,7 +125,8 @@ struct fb
size_t buffer_index = buffer_index(x, y); size_t buffer_index = buffer_index(x, y);
for (size_t iy = 0u; iy < height; iy++) for (size_t iy = 0u; iy < height; iy++)
{ {
m_buffer[buffer_index] = color; m_buffer1[buffer_index] = color;
m_device_buffer[buffer_index] = color;
buffer_index -= m_stride; buffer_index -= m_stride;
} }
} }
@ -153,17 +162,19 @@ struct fb
size_t bitmap_index; size_t bitmap_index;
for (size_t iy = 0u; iy < height; iy++) for (size_t iy = 0u; iy < height; iy++)
{ {
size_t row_buffer_index = buffer_index(x, y);
for (size_t ix = 0u; ix < width; ix++) for (size_t ix = 0u; ix < width; ix++)
{ {
size_t buffer_index = buffer_index(x + ix, y); size_t buffer_index = row_buffer_index + ix;
ubyte alpha = alpha_bitmap[bitmap_index]; ubyte alpha = alpha_bitmap[bitmap_index];
uint current_color = m_buffer[buffer_index]; uint current_color = m_buffer1[buffer_index];
uint in_color_scaled = scale_color(color, alpha); uint in_color_scaled = scale_color(color, alpha);
uint old_color_scaled = scale_color(current_color, 255u - alpha); uint old_color_scaled = scale_color(current_color, 255u - alpha);
uint new_color = old_color_scaled + in_color_scaled; uint new_color = old_color_scaled + in_color_scaled;
m_buffer[buffer_index] = new_color; m_buffer1[buffer_index] = new_color;
bitmap_index++; bitmap_index++;
} }
memcpy32(&m_device_buffer[row_buffer_index], &m_buffer1[row_buffer_index], width);
y--; y--;
} }
} }
@ -202,13 +213,15 @@ struct fb
size_t bitmap_index; size_t bitmap_index;
for (size_t iy = 0u; iy < height; iy++) for (size_t iy = 0u; iy < height; iy++)
{ {
size_t row_buffer_index = buffer_index(x, y);
for (size_t ix = 0u; ix < width; ix++) for (size_t ix = 0u; ix < width; ix++)
{ {
size_t buffer_index = buffer_index(x + ix, y); size_t buffer_index = row_buffer_index + ix;
ubyte alpha = alpha_bitmap[bitmap_index]; ubyte alpha = alpha_bitmap[bitmap_index];
m_buffer[buffer_index] = (alpha << 16u) | (alpha << 8u) | alpha; m_buffer1[buffer_index] = (alpha << 16u) | (alpha << 8u) | alpha;
bitmap_index++; bitmap_index++;
} }
memcpy32(&m_device_buffer[row_buffer_index], &m_buffer1[row_buffer_index], width);
y--; y--;
} }
} }
@ -239,9 +252,14 @@ struct fb
*/ */
static void copy_rows_up(size_t y, size_t height, size_t offset) static void copy_rows_up(size_t y, size_t height, size_t offset)
{ {
memcpy32(&m_buffer[buffer_index(0u, y + height + offset - 1u)], size_t dest_buffer_index = buffer_index(0u, y + height + offset - 1u);
&m_buffer[buffer_index(0u, y + height - 1u)], size_t src_buffer_index = buffer_index(0u, y + height - 1u);
memcpy32(&m_buffer1[dest_buffer_index],
&m_buffer1[src_buffer_index],
(m_stride * height)); (m_stride * height));
memcpy32(&m_device_buffer[dest_buffer_index],
&m_buffer1[dest_buffer_index],
(m_stride * height));
} }
/** /**

View File

@ -57,7 +57,11 @@ void hulk_start()
initialize_cpu(); initialize_cpu();
gdt.initialize(); gdt.initialize();
idt.initialize(); idt.initialize();
fb.initialize(cast(uint *)HULK_VIRTUAL_FRAMEBUFFER_ADDRESS, hulk_header.bootinfo.fb.width, hulk_header.bootinfo.fb.height, hulk_header.bootinfo.fb.stride); fb.initialize(cast(uint *)HULK_VIRTUAL_FRAMEBUFFER_ADDRESS,
cast(uint *)hulk_header.bootinfo.fb_buffer1_phys,
hulk_header.bootinfo.fb.width,
hulk_header.bootinfo.fb.height,
hulk_header.bootinfo.fb.stride);
console.initialize(); console.initialize();
console.clear(); console.clear();
klog.initialize(); klog.initialize();

View File

@ -83,11 +83,16 @@ struct hurl
header.bootinfo.stack_phys, header.bootinfo.stack_phys,
header.stack_size, header.stack_size,
PT_WRITABLE | PT_NO_EXECUTE); PT_WRITABLE | PT_NO_EXECUTE);
/* Map HULK framebuffer. */ /* Map device framebuffer. */
map_range(HULK_VIRTUAL_FRAMEBUFFER_ADDRESS, map_range(HULK_VIRTUAL_FRAMEBUFFER_ADDRESS,
cast(ulong)header.bootinfo.fb.buffer, cast(ulong)header.bootinfo.fb.buffer,
header.bootinfo.fb.height * header.bootinfo.fb.stride * 4u, header.bootinfo.fb.height * header.bootinfo.fb.stride * 4u,
PT_WRITABLE | PT_NO_EXECUTE); PT_WRITABLE | PT_NO_EXECUTE);
/* Map framebuffer buffer1. */
map_range(cast(ulong)header.bootinfo.fb_buffer1_phys,
cast(ulong)header.bootinfo.fb_buffer1_phys,
header.bootinfo.fb.height * header.bootinfo.fb.stride * 4u,
PT_WRITABLE | PT_NO_EXECUTE);
write_cr3(cast(ulong)m_pt_base); write_cr3(cast(ulong)m_pt_base);
} }
@ -143,12 +148,14 @@ struct hurl
* 3) HULK BSS * 3) HULK BSS
* 4) HULK stack * 4) HULK stack
* 5) bootloader page table pages * 5) bootloader page table pages
* 6) framebuffer buffer1
*/ */
size_t usable_memory; size_t usable_memory;
size_t physical_address_limit; size_t physical_address_limit;
const(size_t) fb_size = (header.bootinfo.fb.height * header.bootinfo.fb.stride * 4u + PAGE_SIZE - 1u) & ~(PAGE_SIZE - 1u);
ulong[2][2] reserved = [ ulong[2][2] reserved = [
[header.bootinfo.hulk_phys, LinkerAddresses.hulk_binary_size], [header.bootinfo.hulk_phys, LinkerAddresses.hulk_binary_size],
[cast(ulong)header.bootinfo.fb.buffer, header.bootinfo.fb.height * header.bootinfo.fb.stride * 4u], [cast(ulong)header.bootinfo.fb.buffer, fb_size],
]; ];
for (size_t ri = 0u; ri < reserved.length; ri++) for (size_t ri = 0u; ri < reserved.length; ri++)
{ {
@ -205,6 +212,7 @@ struct hurl
usable_memory += LinkerAddresses.hulk_bss_size; usable_memory += LinkerAddresses.hulk_bss_size;
usable_memory += header.stack_size; usable_memory += header.stack_size;
usable_memory += fb_size;
klog.writefln("Usable memory: %uKB", usable_memory >> 10u); klog.writefln("Usable memory: %uKB", usable_memory >> 10u);
klog.writefln("Kernel size: %uKB", (LinkerAddresses.hulk_binary_size + LinkerAddresses.hulk_bss_size + header.stack_size) >> 10u); klog.writefln("Kernel size: %uKB", (LinkerAddresses.hulk_binary_size + LinkerAddresses.hulk_bss_size + header.stack_size) >> 10u);
} }