#include #include #include #include #include #define WIDTH 640 #define HEIGHT 480 #define DEPTH 24 #define ALIGNMENT 16 // Framebuffer byte alignment. static Framebuffer framebuffer = {}; bool framebuffer_init(uint32_t* error) { MAIL_T uint32_t InitFramebuffer[24] = { /*00*/96, // Size in bytes, aligned to MAIL_ALIGN. /*01*/MAILBOX_REQUEST, /*02*/TAG_FRAMEBUFFER_SET_PHYSICAL_SCREEN_SIZE, 8, MAILBOX_REQUEST, WIDTH, HEIGHT, /*07*/TAG_FRAMEBUFFER_SET_VIRTUAL_SCREEN_SIZE, 8, MAILBOX_REQUEST, WIDTH, HEIGHT, /*12*/TAG_FRAMEBUFFER_SET_DEPTH, 4, MAILBOX_REQUEST, DEPTH, /*16*/TAG_FRAMEBUFFER_ALLOCATE, 8, MAILBOX_REQUEST, ALIGNMENT, 0, /*21*/TAG_END, /*22*/0, 0 // Padding. }; const uint32_t result = mbox_write(PROPERTY_CHANNEL, InitFramebuffer); if (result != MAILBOX_SUCCESS) { goto end; } // The input mail is overwritten with the response. // // TAG_FRAMEBUFFER_ALLOCATE response: // u32 fb base address // u32 fb size // TODO: Do we need & 0x3FFFFFFF? Something about converting GPU address space // to ARM address space. // TODO: Should we read back the pitch, or does pitch match width? framebuffer = (Framebuffer) { .pixels = (Pixel*)((uintptr_t)InitFramebuffer[19] & 0x3FFFFFFF), .size = InitFramebuffer[20], .width = InitFramebuffer[5], .height = InitFramebuffer[6], .depth = InitFramebuffer[15] }; end: *error = result; return result == MAILBOX_SUCCESS; } const Framebuffer* framebuffer_get() { return &framebuffer; } void framebuffer_present(const Pixel* pixels) { memcpy(framebuffer.pixels, pixels, framebuffer.size); } void framebuffer_clear(Pixel colour) { const uint32_t num_channels = framebuffer.depth / 8; const uint32_t num_pixels = framebuffer.size / num_channels; volatile Pixel* fb = framebuffer.pixels; for (size_t i = 0; i < num_pixels; i++) { fb->r = colour.r; fb->g = colour.g; fb->b = colour.b; fb++; } }