* Chia-I Wu <olv@lunarg.com>
*/
+/**
+ * Considering fbdev as an in-kernel window system,
+ *
+ * - opening a device opens a connection
+ * - there is only one window: the framebuffer
+ * - fb_var_screeninfo decides window position, size, and even color format
+ * - there is no pixmap
+ *
+ * Now EGL is built on top of this window system. So we should have
+ *
+ * - the fd as the handle of the native display
+ * - reject all but one native window: NULL
+ * - no pixmap support
+ */
+
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
const struct native_event_handler *event_handler;
struct fb_fix_screeninfo finfo;
- struct fb_var_screeninfo vinfo;
-
+ struct fb_var_screeninfo config_vinfo;
struct native_config config;
- struct native_connector connector;
- struct native_mode mode;
- struct fbdev_surface *current_surface;
+ boolean assume_fixed_vinfo;
};
struct fbdev_surface {
unsigned int sequence_number;
- boolean is_current;
+ struct fbdev_sw_drawable drawable;
};
static INLINE struct fbdev_display *
return TRUE;
}
-static boolean
-fbdev_surface_flush_frontbuffer(struct native_surface *nsurf)
+static enum pipe_format
+vinfo_to_format(const struct fb_var_screeninfo *vinfo)
{
- struct fbdev_surface *fbsurf = fbdev_surface(nsurf);
+ enum pipe_format format = PIPE_FORMAT_NONE;
- if (!fbsurf->is_current)
- return TRUE;
+ /* should also check channel offsets... */
+ switch (vinfo->bits_per_pixel) {
+ case 32:
+ if (vinfo->red.length == 8 &&
+ vinfo->green.length == 8 &&
+ vinfo->blue.length == 8) {
+ format = (vinfo->transp.length == 8) ?
+ PIPE_FORMAT_B8G8R8A8_UNORM : PIPE_FORMAT_B8G8R8X8_UNORM;
+ }
+ break;
+ case 16:
+ if (vinfo->red.length == 5 &&
+ vinfo->green.length == 6 &&
+ vinfo->blue.length == 5 &&
+ vinfo->transp.length == 0)
+ format = PIPE_FORMAT_B5G6R5_UNORM;
+ break;
+ default:
+ break;
+ }
- return resource_surface_present(fbsurf->rsurf,
- NATIVE_ATTACHMENT_FRONT_LEFT, NULL);
+ return format;
}
static boolean
-fbdev_surface_swap_buffers(struct native_surface *nsurf)
+fbdev_surface_update_drawable(struct native_surface *nsurf,
+ const struct fb_var_screeninfo *vinfo)
{
struct fbdev_surface *fbsurf = fbdev_surface(nsurf);
- struct fbdev_display *fbdpy = fbsurf->fbdpy;
- boolean ret = TRUE;
-
- if (fbsurf->is_current) {
- ret = resource_surface_present(fbsurf->rsurf,
- NATIVE_ATTACHMENT_BACK_LEFT, NULL);
+ unsigned x, y, width, height;
+
+ x = vinfo->xoffset;
+ y = vinfo->yoffset;
+ width = MIN2(vinfo->xres, fbsurf->width);
+ height = MIN2(vinfo->yres, fbsurf->height);
+
+ /* sanitize the values */
+ if (x + width > vinfo->xres_virtual) {
+ if (x > vinfo->xres_virtual)
+ width = 0;
+ else
+ width = vinfo->xres_virtual - x;
+ }
+ if (y + height > vinfo->yres_virtual) {
+ if (y > vinfo->yres_virtual)
+ height = 0;
+ else
+ height = vinfo->yres_virtual - y;
}
- resource_surface_swap_buffers(fbsurf->rsurf,
- NATIVE_ATTACHMENT_FRONT_LEFT, NATIVE_ATTACHMENT_BACK_LEFT, TRUE);
- /* the front/back textures are swapped */
- fbsurf->sequence_number++;
- fbdpy->event_handler->invalid_surface(&fbdpy->base,
- &fbsurf->base, fbsurf->sequence_number);
+ fbsurf->drawable.format = vinfo_to_format(vinfo);
+ fbsurf->drawable.x = vinfo->xoffset;
+ fbsurf->drawable.y = vinfo->yoffset;
+ fbsurf->drawable.width = vinfo->xres;
+ fbsurf->drawable.height = vinfo->yres;
- return ret;
+ return (fbsurf->drawable.format != PIPE_FORMAT_NONE &&
+ fbsurf->drawable.width &&
+ fbsurf->drawable.height);
}
static boolean
boolean preserve,
uint swap_interval)
{
- boolean ret;
+ struct fbdev_surface *fbsurf = fbdev_surface(nsurf);
+ struct fbdev_display *fbdpy = fbsurf->fbdpy;
+ boolean ret = FALSE;
- if (preserve || swap_interval)
+ if (swap_interval)
+ return FALSE;
+ if (natt != NATIVE_ATTACHMENT_BACK_LEFT)
return FALSE;
- switch (natt) {
- case NATIVE_ATTACHMENT_FRONT_LEFT:
- ret = fbdev_surface_flush_frontbuffer(nsurf);
- break;
- case NATIVE_ATTACHMENT_BACK_LEFT:
- ret = fbdev_surface_swap_buffers(nsurf);
- break;
- default:
- ret = FALSE;
- break;
+ if (!fbdpy->assume_fixed_vinfo) {
+ struct fb_var_screeninfo vinfo;
+
+ memset(&vinfo, 0, sizeof(vinfo));
+ if (ioctl(fbdpy->fd, FBIOGET_VSCREENINFO, &vinfo))
+ return FALSE;
+
+ /* present the surface */
+ if (fbdev_surface_update_drawable(&fbsurf->base, &vinfo)) {
+ ret = resource_surface_present(fbsurf->rsurf,
+ natt, (void *) &fbsurf->drawable);
+ }
+
+ fbsurf->width = vinfo.xres;
+ fbsurf->height = vinfo.yres;
+
+ if (resource_surface_set_size(fbsurf->rsurf,
+ fbsurf->width, fbsurf->height)) {
+ /* surface resized */
+ fbsurf->sequence_number++;
+ fbdpy->event_handler->invalid_surface(&fbdpy->base,
+ &fbsurf->base, fbsurf->sequence_number);
+ }
+ }
+ else {
+ /* the drawable never changes */
+ ret = resource_surface_present(fbsurf->rsurf,
+ natt, (void *) &fbsurf->drawable);
}
return ret;
}
static struct native_surface *
-fbdev_display_create_scanout_surface(struct native_display *ndpy,
- const struct native_config *nconf,
- uint width, uint height)
+fbdev_display_create_window_surface(struct native_display *ndpy,
+ EGLNativeWindowType win,
+ const struct native_config *nconf)
{
struct fbdev_display *fbdpy = fbdev_display(ndpy);
struct fbdev_surface *fbsurf;
+ struct fb_var_screeninfo vinfo;
+
+ /* there is only one native window: NULL */
+ if (win)
+ return NULL;
fbsurf = CALLOC_STRUCT(fbdev_surface);
if (!fbsurf)
return NULL;
fbsurf->fbdpy = fbdpy;
- fbsurf->width = width;
- fbsurf->height = height;
+
+ /* get current vinfo */
+ if (fbdpy->assume_fixed_vinfo) {
+ vinfo = fbdpy->config_vinfo;
+ }
+ else {
+ memset(&vinfo, 0, sizeof(vinfo));
+ if (ioctl(fbdpy->fd, FBIOGET_VSCREENINFO, &vinfo)) {
+ FREE(fbsurf);
+ return NULL;
+ }
+ }
+
+ fbsurf->width = vinfo.xres;
+ fbsurf->height = vinfo.yres;
+
+ if (!fbdev_surface_update_drawable(&fbsurf->base, &vinfo)) {
+ FREE(fbsurf);
+ return NULL;
+ }
fbsurf->rsurf = resource_surface_create(fbdpy->base.screen,
nconf->color_format,
PIPE_BIND_RENDER_TARGET |
- PIPE_BIND_DISPLAY_TARGET |
- PIPE_BIND_SCANOUT);
+ PIPE_BIND_DISPLAY_TARGET);
if (!fbsurf->rsurf) {
FREE(fbsurf);
return NULL;
return &fbsurf->base;
}
+static struct native_surface *
+fbdev_display_create_scanout_surface(struct native_display *ndpy,
+ const struct native_config *nconf,
+ uint width, uint height)
+{
+ return fbdev_display_create_window_surface(ndpy,
+ (EGLNativeWindowType) NULL, nconf);
+}
+
static boolean
fbdev_display_program(struct native_display *ndpy, int crtc_idx,
struct native_surface *nsurf, uint x, uint y,
const struct native_connector **nconns, int num_nconns,
const struct native_mode *nmode)
{
- struct fbdev_display *fbdpy = fbdev_display(ndpy);
- struct fbdev_surface *fbsurf = fbdev_surface(nsurf);
-
- if (x || y)
- return FALSE;
-
- if (fbdpy->current_surface) {
- if (fbdpy->current_surface == fbsurf)
- return TRUE;
- fbdpy->current_surface->is_current = FALSE;
- }
-
- if (fbsurf)
- fbsurf->is_current = TRUE;
- fbdpy->current_surface = fbsurf;
-
return TRUE;
}
static const struct native_mode **
fbdev_display_get_modes(struct native_display *ndpy,
- const struct native_connector *nconn,
- int *num_modes)
+ const struct native_connector *nconn,
+ int *num_modes)
{
- struct fbdev_display *fbdpy = fbdev_display(ndpy);
+ static struct native_mode mode;
const struct native_mode **modes;
+ if (!mode.desc) {
+ struct fbdev_display *fbdpy = fbdev_display(ndpy);
+ mode.desc = "Current Mode";
+ mode.width = fbdpy->config_vinfo.xres;
+ mode.height = fbdpy->config_vinfo.yres;
+ mode.refresh_rate = 60 * 1000; /* dummy */
+ }
+
modes = MALLOC(sizeof(*modes));
if (modes) {
- modes[0] = &fbdpy->mode;
+ modes[0] = &mode;
if (num_modes)
*num_modes = 1;
}
fbdev_display_get_connectors(struct native_display *ndpy, int *num_connectors,
int *num_crtc)
{
- struct fbdev_display *fbdpy = fbdev_display(ndpy);
+ static struct native_connector connector;
const struct native_connector **connectors;
connectors = MALLOC(sizeof(*connectors));
if (connectors) {
- connectors[0] = &fbdpy->connector;
+ connectors[0] = &connector;
if (num_connectors)
*num_connectors = 1;
}
return connectors;
}
-static struct native_display_modeset fbdev_display_modeset = {
+/* remove modeset support one day! */
+static const struct native_display_modeset fbdev_display_modeset = {
.get_connectors = fbdev_display_get_connectors,
.get_modes = fbdev_display_get_modes,
.create_scanout_surface = fbdev_display_create_scanout_surface,
int val;
switch (param) {
- case NATIVE_PARAM_USE_NATIVE_BUFFER:
case NATIVE_PARAM_PRESERVE_BUFFER:
+ val = 1;
+ break;
+ case NATIVE_PARAM_USE_NATIVE_BUFFER:
case NATIVE_PARAM_MAX_SWAP_INTERVAL:
default:
val = 0;
}
static boolean
-fbdev_display_init_modes(struct native_display *ndpy)
-{
- struct fbdev_display *fbdpy = fbdev_display(ndpy);
- struct native_mode *nmode = &fbdpy->mode;
-
- nmode->desc = "Current Mode";
- nmode->width = fbdpy->vinfo.xres;
- nmode->height = fbdpy->vinfo.yres;
- nmode->refresh_rate = 60 * 1000; /* dummy */
-
- return TRUE;
-}
-
-static boolean
-fbdev_display_init_connectors(struct native_display *ndpy)
-{
- return TRUE;
-}
-
-static enum pipe_format
-vinfo_to_format(const struct fb_var_screeninfo *vinfo)
-{
- enum pipe_format format = PIPE_FORMAT_NONE;
-
- switch (vinfo->bits_per_pixel) {
- case 32:
- if (vinfo->red.length == 8 &&
- vinfo->green.length == 8 &&
- vinfo->blue.length == 8) {
- format = (vinfo->transp.length == 8) ?
- PIPE_FORMAT_B8G8R8A8_UNORM : PIPE_FORMAT_B8G8R8X8_UNORM;
- }
- break;
- case 16:
- if (vinfo->red.length == 5 &&
- vinfo->green.length == 6 &&
- vinfo->blue.length == 5 &&
- vinfo->transp.length == 0)
- format = PIPE_FORMAT_B5G6R5_UNORM;
- break;
- default:
- break;
- }
-
- return format;
-}
-
-static boolean
-fbdev_display_init_configs(struct native_display *ndpy)
-{
- struct fbdev_display *fbdpy = fbdev_display(ndpy);
- struct native_config *nconf = &fbdpy->config;
-
- nconf->color_format = vinfo_to_format(&fbdpy->vinfo);
- if (nconf->color_format == PIPE_FORMAT_NONE)
- return FALSE;
-
- nconf->buffer_mask =
- (1 << NATIVE_ATTACHMENT_FRONT_LEFT) |
- (1 << NATIVE_ATTACHMENT_BACK_LEFT);
-
- nconf->scanout_bit = TRUE;
-
- return TRUE;
-}
-
-static boolean
fbdev_display_init_screen(struct native_display *ndpy)
{
struct fbdev_display *fbdpy = fbdev_display(ndpy);
struct sw_winsys *ws;
- ws = fbdev_create_sw_winsys(fbdpy->fd, fbdpy->config.color_format);
+ ws = fbdev_create_sw_winsys(fbdpy->fd);
if (!ws)
return FALSE;
return TRUE;
}
+static boolean
+fbdev_display_init_config(struct native_display *ndpy)
+{
+ struct fbdev_display *fbdpy = fbdev_display(ndpy);
+ struct native_config *nconf = &fbdpy->config;
+
+ if (ioctl(fbdpy->fd, FBIOGET_VSCREENINFO, &fbdpy->config_vinfo))
+ return FALSE;
+
+ nconf->color_format = vinfo_to_format(&fbdpy->config_vinfo);
+ if (nconf->color_format == PIPE_FORMAT_NONE)
+ return FALSE;
+
+ nconf->buffer_mask = (1 << NATIVE_ATTACHMENT_BACK_LEFT);
+
+ nconf->window_bit = TRUE;
+
+ return TRUE;
+}
+
static struct native_display *
fbdev_display_create(int fd, const struct native_event_handler *event_handler)
{
if (ioctl(fbdpy->fd, FBIOGET_FSCREENINFO, &fbdpy->finfo))
goto fail;
- if (ioctl(fbdpy->fd, FBIOGET_VSCREENINFO, &fbdpy->vinfo))
- goto fail;
-
if (fbdpy->finfo.visual != FB_VISUAL_TRUECOLOR ||
fbdpy->finfo.type != FB_TYPE_PACKED_PIXELS)
goto fail;
- if (!fbdev_display_init_configs(&fbdpy->base) ||
- !fbdev_display_init_connectors(&fbdpy->base) ||
- !fbdev_display_init_modes(&fbdpy->base))
+ if (!fbdev_display_init_config(&fbdpy->base))
goto fail;
+ fbdpy->assume_fixed_vinfo = TRUE;
+
fbdpy->base.init_screen = fbdev_display_init_screen;
fbdpy->base.destroy = fbdev_display_destroy;
fbdpy->base.get_param = fbdev_display_get_param;
fbdpy->base.get_configs = fbdev_display_get_configs;
+ fbdpy->base.create_window_surface = fbdev_display_create_window_surface;
+
+ /* we'd like to remove modeset support one day */
+ fbdpy->config.scanout_bit = TRUE;
fbdpy->base.modeset = &fbdev_display_modeset;
return &fbdpy->base;
struct sw_winsys base;
int fd;
- enum pipe_format format;
struct fb_fix_screeninfo finfo;
- void *fbmem;
unsigned rows;
unsigned stride;
};
static void
fbdev_displaytarget_display(struct sw_winsys *ws,
struct sw_displaytarget *dt,
- void *context_private)
+ void *winsys_private)
{
struct fbdev_sw_winsys *fbdev = fbdev_sw_winsys(ws);
- struct fbdev_sw_displaytarget *fbdt = fbdev_sw_displaytarget(dt);
- unsigned rows, len, i;
+ struct fbdev_sw_displaytarget *src = fbdev_sw_displaytarget(dt);
+ const struct fbdev_sw_drawable *dst =
+ (const struct fbdev_sw_drawable *) winsys_private;
+ unsigned height, row_offset, row_len, i;
+ void *fbmem;
+
+ /* FIXME format conversion */
+ if (dst->format != src->format) {
+ assert(0);
+ return;
+ }
- rows = MIN2(fbdt->height, fbdev->rows);
- len = util_format_get_stride(fbdt->format, fbdt->width);
- len = MIN2(len, fbdev->stride);
+ height = dst->height;
+ if (dst->y + dst->height > fbdev->rows) {
+ /* nothing to copy */
+ if (dst->y >= fbdev->rows)
+ return;
- for (i = 0; i < rows; i++) {
- void *dst = fbdev->fbmem + fbdev->stride * i;
- void *src = fbdt->data + fbdt->stride * i;
+ height = fbdev->rows - dst->y;
+ }
+
+ row_offset = util_format_get_stride(dst->format, dst->x);
+ row_len = util_format_get_stride(dst->format, dst->width);
+ if (row_offset + row_len > fbdev->stride) {
+ /* nothing to copy */
+ if (row_offset >= fbdev->stride)
+ return;
- memcpy(dst, src, len);
+ row_len = fbdev->stride - row_offset;
}
+
+ fbmem = mmap(0, fbdev->finfo.smem_len,
+ PROT_WRITE, MAP_SHARED, fbdev->fd, 0);
+ if (fbmem == MAP_FAILED)
+ return;
+
+ for (i = 0; i < height; i++) {
+ char *from = (char *) src->data + src->stride * i;
+ char *to = (char *) fbmem + fbdev->stride * (dst->y + i) + row_offset;
+
+ memcpy(to, from, row_len);
+ }
+
+ munmap(fbmem, fbdev->finfo.smem_len);
}
static void
unsigned alignment,
unsigned *stride)
{
- struct fbdev_sw_winsys *fbdev = fbdev_sw_winsys(ws);
struct fbdev_sw_displaytarget *fbdt;
unsigned nblocksy, size, format_stride;
- if (fbdev->format != format)
- return NULL;
-
fbdt = CALLOC_STRUCT(fbdev_sw_displaytarget);
if (!fbdt)
return NULL;
unsigned tex_usage,
enum pipe_format format)
{
- struct fbdev_sw_winsys *fbdev = fbdev_sw_winsys(ws);
- return (fbdev->format == format);
+ return TRUE;
}
static void
{
struct fbdev_sw_winsys *fbdev = fbdev_sw_winsys(ws);
- munmap(fbdev->fbmem, fbdev->finfo.smem_len);
FREE(fbdev);
}
struct sw_winsys *
-fbdev_create_sw_winsys(int fd, enum pipe_format format)
+fbdev_create_sw_winsys(int fd)
{
struct fbdev_sw_winsys *fbdev;
return NULL;
fbdev->fd = fd;
- fbdev->format = format;
if (ioctl(fbdev->fd, FBIOGET_FSCREENINFO, &fbdev->finfo)) {
FREE(fbdev);
return NULL;
}
- fbdev->fbmem = mmap(0, fbdev->finfo.smem_len,
- PROT_WRITE, MAP_SHARED, fbdev->fd, 0);
- if (fbdev->fbmem == MAP_FAILED) {
- FREE(fbdev);
- return NULL;
- }
-
fbdev->rows = fbdev->finfo.smem_len / fbdev->finfo.line_length;
fbdev->stride = fbdev->finfo.line_length;