1
0
Fork 0
forked from AbleOS/ableos
ableos/sysdata/programs/fb_driver/src/lib.hb

88 lines
2.7 KiB
Plaintext

.{memory, math} := @use("../../../libraries/stn/src/lib.hb");
.{ColorBGRA, blend} := @use("rel:color.hb")
FB_WIDTH := 1024
FB_HEIGHT := 768
FB_PIXELS := FB_WIDTH * FB_HEIGHT
FB_BYTES := FB_PIXELS << 2
// actual enforced max copy size is 0xFFFF, but this was faster
MAX_COPY_SIZE := 0x1800
COPY_PIXELS := math.min(MAX_COPY_SIZE, FB_BYTES) >> 2
PARTITIONS := FB_PIXELS / COPY_PIXELS
TOTAL_PAGES := 1 + FB_BYTES >> 12
Buffer := struct {write: ^ColorBGRA, copy: ^[ColorBGRA; COPY_PIXELS]}
Point := struct {x: int, y: int}
Transform := struct {width: int, height: int}
front_buffer_ptr := @as(^ColorBGRA, @bitcast(0xFFFF8000C0000000))
front_buffer_copy := @as(^[ColorBGRA; COPY_PIXELS], @bitcast(front_buffer_ptr))
get_front_buffer := fn(): Buffer {
// trying to return front_buffer_ptr or front_buffer_copy causes reg id leak
buffer := Buffer.{write: front_buffer_ptr, copy: front_buffer_copy}
return buffer
}
/* this is separate to create_raw_buffer because returning a Buffer from
create_raw_buffer causes reg id leak */
create_buffer := fn(): Buffer {
ptr := @inline(create_raw_buffer)
buffer := Buffer.{write: ptr, copy: @as(^[ColorBGRA; COPY_PIXELS], @bitcast(ptr))}
return buffer
}
create_raw_buffer := fn(): ^ColorBGRA {
if TOTAL_PAGES <= 0xFF {
return @bitcast(@inline(memory.request_page, TOTAL_PAGES))
}
ptr := @inline(memory.request_page, 255)
remaining := TOTAL_PAGES - 0xFF
loop if remaining <= 0 break else {
if remaining < 0xFF {
memory.request_page(remaining)
} else {
memory.request_page(0xFF)
}
remaining -= 0xFF
}
return @bitcast(ptr)
}
// sets the buffer to the color. very fast.
clear := fn(buffer: Buffer, color: ColorBGRA): void {
n := 0
// write the first pixel chunk
loop if n >= COPY_PIXELS break else {
*(buffer.write + n) = color
n += 1
}
n = 1
// copy that pixel chunk through the buffer, taking advantage of memory copying
loop if n >= PARTITIONS break else {
*(buffer.copy + n) = *buffer.copy
n += 1
}
return
}
// only required to be called when using a back buffer. if using single-buffered rendering, do not call this.
present := fn(buffer: Buffer): void {
n := 0
// copy chunks of the read buffer to the front buffer
loop if n >= PARTITIONS break else {
*(front_buffer_copy + n) = *(buffer.copy + n)
n += 1
}
return
}
// composites the contents of buffer1 into buffer2, accounting for alpha transparency
// i dont know if it works. i have not tested it. it probably doesnt work
composite := fn(buffer1: Buffer, buffer2: Buffer): void {
n := 0
loop if n == FB_PIXELS break else {
bg := *(buffer2.write + n);
*(buffer2.write + n) = blend(*(buffer1.write + n), bg)
n += 1
}
return
}
screenidx := fn(pos: Point): int {
return pos.x + FB_WIDTH * pos.y
}