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
{
/** Frame buffer base address. */
private __gshared static uint * m_buffer;
/** Device frame buffer base address. */
private __gshared static uint * m_device_buffer;
/** Frame buffer 1 base address. */
private __gshared static uint * m_buffer1;
/** Frame buffer width. */
private __gshared static uint m_width;
@ -47,14 +50,16 @@ struct fb
/**
* 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 height Frame buffer height.
* @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_height = height;
m_stride = stride;
@ -68,7 +73,8 @@ struct fb
*/
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++)
{
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++;
}
}
@ -101,7 +108,8 @@ struct fb
static void hline(size_t x, size_t y, size_t width, uint color)
{
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);
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;
}
}
@ -153,17 +162,19 @@ struct fb
size_t bitmap_index;
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++)
{
size_t buffer_index = buffer_index(x + ix, y);
size_t buffer_index = row_buffer_index + ix;
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 old_color_scaled = scale_color(current_color, 255u - alpha);
uint new_color = old_color_scaled + in_color_scaled;
m_buffer[buffer_index] = new_color;
m_buffer1[buffer_index] = new_color;
bitmap_index++;
}
memcpy32(&m_device_buffer[row_buffer_index], &m_buffer1[row_buffer_index], width);
y--;
}
}
@ -202,13 +213,15 @@ struct fb
size_t bitmap_index;
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++)
{
size_t buffer_index = buffer_index(x + ix, y);
size_t buffer_index = row_buffer_index + ix;
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++;
}
memcpy32(&m_device_buffer[row_buffer_index], &m_buffer1[row_buffer_index], width);
y--;
}
}
@ -239,9 +252,14 @@ struct fb
*/
static void copy_rows_up(size_t y, size_t height, size_t offset)
{
memcpy32(&m_buffer[buffer_index(0u, y + height + offset - 1u)],
&m_buffer[buffer_index(0u, y + height - 1u)],
size_t dest_buffer_index = buffer_index(0u, y + height + offset - 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));
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();
gdt.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.clear();
klog.initialize();

View File

@ -83,11 +83,16 @@ struct hurl
header.bootinfo.stack_phys,
header.stack_size,
PT_WRITABLE | PT_NO_EXECUTE);
/* Map HULK framebuffer. */
/* Map device framebuffer. */
map_range(HULK_VIRTUAL_FRAMEBUFFER_ADDRESS,
cast(ulong)header.bootinfo.fb.buffer,
header.bootinfo.fb.height * header.bootinfo.fb.stride * 4u,
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);
}
@ -143,12 +148,14 @@ struct hurl
* 3) HULK BSS
* 4) HULK stack
* 5) bootloader page table pages
* 6) framebuffer buffer1
*/
size_t usable_memory;
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 = [
[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++)
{
@ -205,6 +212,7 @@ struct hurl
usable_memory += LinkerAddresses.hulk_bss_size;
usable_memory += header.stack_size;
usable_memory += fb_size;
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);
}