一、概述
framebuffer是啥就不用详细说了吧,需要注意的是android emulator的framebuffer貌似用处不大,因为我之前用android emulator运行x86镜像时,可能是分辨率选得太大了,/dev/graphics/fb0文件都没有产生,系统却可以正常跑,因为系统用的是DRM方式。
另外,GOLDFISH-VIRTUAL-HARDWARE.TXT说了
IMPORTANT NOTE: When GPU emulation is enabled, the framebuffer will typically only be used during boot.
所以,本篇可以跳过不看。
二、驱动
老规矩,先看文档
V. Goldfish framebuffer:
========================
Relevant files:
$QEMU/hw/android/goldfish/fb.c
$KERNEL/drivers/video/goldfish_fb.c
Device properties:
Name: goldfish_fb
Id: 0 to N (only one used in practice).
IrqCount: 0
I/O Registers:
0x00 GET_WIDTH R: Read framebuffer width in pixels.
0x04 GET_HEIGHT R: Read framebuffer height in pixels.
0x08 INT_STATUS
0x0c INT_ENABLE
0x10 SET_BASE
0x14 SET_ROTATION
0x18 SET_BLANK W: Set 'blank' flag.
0x1c GET_PHYS_WIDTH R: Read framebuffer width in millimeters.
0x20 GET_PHYS_HEIGHT R: Read framebuffer height in millimeters.
0x24 GET_FORMAT R: Read framebuffer pixel format.
The framebuffer device is a bit peculiar, because it uses, in addition to the
typical I/O registers and IRQs, a large area of physical memory, allocated by
the kernel, but visible to the emulator, to store a large pixel buffer.
The emulator is responsible for displaying the framebuffer content in its UI
window, which can be rotated, as instructed by the kernel.
IMPORTANT NOTE: When GPU emulation is enabled, the framebuffer will typically
only be used during boot. Note that GPU emulation doesn't rely on a specific
virtual GPU device, however, it uses the "QEMU Pipe" device described below.
For more information, please read:
https://android.googlesource.com/platform/sdk/+/master/emulator/opengl/DESIGN
On boot, the kernel will read various properties of the framebuffer:
IO_READ(GET_WIDTH) and IO_READ(GET_HEIGHT) return the width and height of
the framebuffer in pixels. Note that a 'row' corresponds to consecutive bytes
in memory, but doesn't necessarily to an horizontal line on the final display,
due to possible rotation (see SET_ROTATION below).
IO_READ(GET_PHYS_WIDTH) and IO_READ(GET_PHYS_HEIGHT) return the emulated
physical width and height in millimeters, this is later used by the kernel
and the platform to determine the device's emulated density.
IO_READ(GET_FORMAT) returns a value matching the format of pixels in the
framebuffer. Note that these values are specified by the Android hardware
abstraction layer (HAL) and cannot change:
0x01 HAL_PIXEL_FORMAT_BRGA_8888
0x02 HAL_PIXEL_FORMAT_RGBX_8888
0x03 HAL_PIXEL_FORMAT_RGB_888
0x04 HAL_PIXEL_FORMAT_RGB_565
0x05 HAL_PIXEL_FORMAT_BGRA_8888
0x06 HAL_PIXEL_FORMAT_RGBA_5551
0x08 HAL_PIXEL_FORMAT_RGBA_4444
HOWEVER, the kernel driver only expects a value of HAL_PIXEL_FORMAT_RGB_565
at the moment. Until this is fixed, the virtual device should always return
the value 0x04 here. Rows are not padded, so the size in bytes of a single
framebuffer will always be exactly 'width * heigth * 2'.
Note that GPU emulation doesn't have this limitation and can use and display
32-bit surfaces properly, because it doesn't use the framebuffer.
The device has a 'blank' flag. When set to 1, the UI should only display an
empty/blank framebuffer, ignoring the content of the framebuffer memory.
It is set with IO_WRITE(SET_BLANK, <value>), where value can be 1 or 0. This is
used when simulating suspend/resume.
IMPORTANT: The framebuffer memory is allocated by the kernel, which will send
its physical address to the device by using IO_WRITE(SET_BASE, <address>).
The kernel really allocates a memory buffer large enough to hold *two*
framebuffers, in order to implement panning / double-buffering. This also means
that calls to IO_WRITE(SET_BASE, <address>) will be frequent.
The allocation happens with dma_alloc_writecombine() on ARM, which can only
allocate a maximum of 4 MB, this limits the size of each framebuffer to 2 MB,
which may not be enough to emulate high-density devices :-(
For other architectures, dma_alloc_coherent() is used instead, and has the same
upper limit / limitation.
TODO(digit): Explain how it's possible to raise this limit by modifyinf
CONSISTENT_DMA_SIZE and/or MAX_ORDER in the kernel configuration.
The device uses a single IRQ to notify the kernel of several events. When it
is raised, the kernel IRQ handler must IO_READ(INT_STATUS), which will return
a value containing the following bit flags:
bit 0: Set to 1 to i