#pragma once // The display class: what a consumer talks to instead of a driver. // // A compositor should ask for "the display" and get whatever is bound -- // today the VBE framebuffer, later virtio-gpu. Without this, every consumer // names a driver, and adding the second display driver means editing all of // them. That is not hypothetical here: the framebuffer's physical address was // once hardcoded in three separate places. // // Found with device_find_class(DEVCLASS_DISPLAY); see include/device.h. struct device; struct display_mode { int width, height; int bpp; uint32 stride; // bytes per row of the *visible* framebuffer }; struct display_ops { void (*mode)(struct device *, struct display_mode *); // The buffer to draw into, and its stride. Returns 0 if double buffering is // unavailable, in which case the caller should draw directly and accept // tearing rather than not drawing at all. // // Allocated on first call, never at boot: it is around two megabytes at // 800x600, and a machine whose compositor never starts should not pay that. void *(*acquire)(struct device *, uint32 *stride_out); // Copy a rectangle of the back buffer to the display. Coordinates are in // pixels; the whole screen is (0, 0, width, height). void (*present)(struct device *, int x, int y, int w, int h); // Block until the display is between frames. Optional -- a driver that // cannot tell leaves this null, and present() then simply tears less than // drawing directly would. void (*wait_vblank)(struct device *); // The physical address this device is scanning out from. // // Which answers a question acquire() cannot: **is this screen the console's // screen, or another one?** The buffer acquire() returns is not the answer, // because a driver is free to hand back a back buffer it will later copy // onto the console's own framebuffer -- vga_fb does exactly that, and a // console mirror that believed the pointer copied the console onto itself // through two megabytes of intermediate. // // A fact about the hardware rather than a policy, so a driver cannot get it // subtly wrong: compare it with gfx_fb_phys(). Optional; a driver that // leaves it null is assumed to be the console's, which is the safe way round // -- it costs a second screen nothing is drawn on, not a wrong picture. uint64 (*scanout_phys)(struct device *); }; // The bound display, or 0. Convenience over device_find_class(). struct device *display_get(void); // Wrappers that do nothing gracefully when there is no display or the driver // left an op null, so callers are not each written around a maybe-null vtable. int display_mode(struct display_mode *out); void *display_acquire(uint32 *stride_out); void display_present(int x, int y, int w, int h); void display_wait_vblank(void); // Drive the whole path once and draw a test pattern. `echo d > /proc/sysrq`. void display_selftest(void); // Draw a text specimen through the display class. `echo t > /proc/sysrq`. void text_selftest(void);