[cairo] cairo_paint crashing with 24 bit bpp
victorascroft at gmail.com
victorascroft at gmail.com
Fri Feb 27 04:22:28 PST 2015
Hello,
I am using a Freescale Vybrid module and running the 3.18.5 kernel on
it. Vybrid has a framebuffer driver and has the concept of multiple
layers. The driver is not in the mainline due to it being a framebuffer
driver and not DRM based.
http://thread.gmane.org/gmane.linux.ports.arm.kernel/260784/focus=269349
It allows for setting BPP to 16, 24 and 32 for each of the framebuffer
layers. The alpha values of each of the five framebuffer layers can be
set by using IOCTL call provided by the driver. The layers have priority
with the 0 layer being highest priority and the highest layer having
lower priority. Depending on the alpha value of each of the individual
layers, these interact to render a blended image. For example, I can set
the alpha value of fb0 to 150 and then set the fb1 to have an alpha
value of 200. What I write to fb1 will appear blended with what is on
fb0.
Now to write to the individual fbx I am using Cairo. The cairo version
being used is 1.12.16 build using Openembedded. I do have LXDM and X on
it but both are disabled and not required for the use of framebuffer
which I want. X/LXDM is not much of use here as it does not seem to work
with 32 bit bpp. Openembedded build is based on Yocto daisy.
On using 16 bit bpp and 32 bit bpp I can write successfully to any of
the framebuffers and get the results I am expecting. The alpha value for
each of these framebuffers is being controlled by hardware and the
driver. At 24 bit bpp, calling cairo_paint crashes. I tried using
cairo_paint_with_alpha which also crashes if an alpha value > 0.0 is
specified. If I set alpha to 0.0 and then call it, I can see the images
being rendered but severely distorted kind of.
I used gdb to track and make sure that it is cairo_paint where this
crashes, using breakpoints at addresses inside cairo_paint to confirm.
I do not have the disassembled output of cairo library with source, but,
this is probably at the cr->backend->paint call. I was only able to
trace the address based on PLT entries in disassembled output of my
cairo application.
Not being too well versed with cairo or graphics, can someone point me
in the right direction here and give some inputs as to why I am
observing this with 24 bit bpp.
My code piece is as below:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <linux/types.h>
#include <linux/ioctl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <cairo/cairo.h>
#define DELAY_IN_SECS 5
#define SCALE_WIDTH 256.0
#define SCALE_HEIGHT 256.0
typedef struct _cairo_linuxfb_device {
int fb_fd;
char *fb_data;
long fb_screensize;
struct fb_var_screeninfo fb_vinfo;
struct fb_fix_screeninfo fb_finfo;
} cairo_linuxfb_device_t;
/* Destroy a cairo surface */
void cairo_linuxfb_surface_destroy(void *device)
{
cairo_linuxfb_device_t *dev = (cairo_linuxfb_device_t *)device;
if (dev == NULL)
return;
munmap(dev->fb_data, dev->fb_screensize);
close(dev->fb_fd);
free(dev);
}
/* Create a cairo surface using the specified framebuffer */
cairo_surface_t *cairo_linuxfb_surface_create(const char *fb_name)
{
int color_input;
cairo_linuxfb_device_t *device;
cairo_surface_t *surface;
/* Use fb0 if no fram buffer is specified */
if (fb_name == NULL) {
fb_name = "/dev/fb0";
}
device = malloc(sizeof(*device));
if (!device) {
perror("Error: cannot allocate memory\n");
exit(1);
}
// Open the file for reading and writing
device->fb_fd = open(fb_name, O_RDWR);
if (device->fb_fd == -1) {
perror("Error: cannot open framebuffer device");
goto handle_allocate_error;
}
// Get variable screen information
if (ioctl(device->fb_fd, FBIOGET_VSCREENINFO, &device->fb_vinfo)
== -1) {
perror("Error: reading variable information");
goto handle_ioctl_error;
}
// Figure out the size of the screen in bytes
device->fb_screensize = device->fb_vinfo.xres *
device->fb_vinfo.yres
* device->fb_vinfo.bits_per_pixel / 8;
// Map the device to memory
device->fb_data = (char *)mmap(0, device->fb_screensize,
PROT_READ | PROT_WRITE,
MAP_SHARED,
device->fb_fd, 0);
if ((int)device->fb_data == -1) {
perror("Error: failed to map framebuffer device to
memory");
goto handle_ioctl_error;
}
// Get fixed screen information
if (ioctl(device->fb_fd, FBIOGET_FSCREENINFO, &device->fb_finfo)
== -1) {
perror("Error reading fixed information");
goto handle_ioctl_error;
}
printf("1. CAIRO_FORMAT_RGB16_565\n");
printf("2. CAIRO_FORMAT_RGB24\n");
printf("3. CAIRO_FORMAT_ARGB32\n");
printf("Enter the color input:\t");
scanf("%d", &color_input);
switch(color_input) {
case 1:
/* Create the cairo surface which will be used to draw
to */
surface = cairo_image_surface_create_for_data(device->fb_data,
CAIRO_FORMAT_RGB16_565,
device->fb_vinfo.xres,
device->fb_vinfo.yres,
cairo_format_stride_for_width(CAIRO_FORMAT_RGB16_565,
device->fb_vinfo.xres));
break;
case 2:
/* Create the cairo surface which will be used to draw
to */
surface = cairo_image_surface_create_for_data(device->fb_data,
CAIRO_FORMAT_RGB24,
device->fb_vinfo.xres,
device->fb_vinfo.yres,
cairo_format_stride_for_width(CAIRO_FORMAT_RGB24,
device->fb_vinfo.xres));
break;
case 3:
/* Create the cairo surface which will be used to draw
to */
surface = cairo_image_surface_create_for_data(device->fb_data,
CAIRO_FORMAT_ARGB32,
device->fb_vinfo.xres,
device->fb_vinfo.yres,
cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32,
device->fb_vinfo.xres));
break;
default:
printf("Invalid input. Selecting
CAIRO_FORMAT_RGB16_565\n");
/* Create the cairo surface which will be used to draw
to */
surface = cairo_image_surface_create_for_data(device->fb_data,
CAIRO_FORMAT_RGB16_565,
device->fb_vinfo.xres,
device->fb_vinfo.yres,
cairo_format_stride_for_width(CAIRO_FORMAT_RGB16_565,
device->fb_vinfo.xres));
break;
}
if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
perror("Error in creating cairo surface\n");
goto handle_ioctl_error;
}
cairo_surface_set_user_data(surface, NULL, device,
&cairo_linuxfb_surface_destroy);
return surface;
handle_ioctl_error:
close(device->fb_fd);
handle_allocate_error:
free(device);
exit(1);
}
int main(int argc, char *argv[]) {
int image_width;
int image_height;
float cairo_alpha_value;
char frame_buffer_number;
char fb_node[16] = {0};
cairo_surface_t *surface;
cairo_surface_t *image;
cairo_t *cr;
if (argc != 2) {
printf("Usage: ./cairo /path/to/png/image\n");
exit(1);
}
if (strstr(argv[1], ".png") == NULL) {
printf("Only png images are supported with this
example\n");
exit(1);
}
printf("Enter frame buffer number:\t");
scanf("%c", &frame_buffer_number);
sprintf(fb_node, "/dev/fb");
fb_node[strlen(fb_node)] = frame_buffer_number;
fb_node[strlen(fb_node)] = '\0';
printf("Frame buffer node is: %s\n", fb_node);
surface = cairo_linuxfb_surface_create(fb_node);
cr = cairo_create(surface);
if (cairo_status(cr) != CAIRO_STATUS_SUCCESS) {
printf("Error in creating cairo surface\n");
cairo_surface_destroy(surface);
exit(1);
}
printf("Enter the cairo alpha value to paint with:\t");
scanf("%f", &cairo_alpha_value);
/*
* We clear the cairo surface here before drawing
* This is required in case something was drawn on this surface
* previously, the previous contents would not be cleared
without this.
*/
cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
cairo_paint_with_alpha(cr, cairo_alpha_value);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
cairo_select_font_face(cr, "serif", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size(cr, 32.0);
cairo_set_source_rgb(cr, 1.0, 1.0, 0.0);
cairo_move_to(cr, 100, 300);
cairo_show_text(cr, "Toradex Cairo Example!");
/* Wait for the result of drawing operation to persist for the
user to see */
sleep(DELAY_IN_SECS);
/* Clear the surface and prepare for a new drawing operation */
cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
cairo_paint_with_alpha(cr, cairo_alpha_value);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
image = cairo_image_surface_create_from_png(argv[1]);
image_width = cairo_image_surface_get_width(image);
image_height = cairo_image_surface_get_height(image);
/* Scale the image arbitrarily */
cairo_scale(cr, SCALE_WIDTH/image_width,
SCALE_HEIGHT/image_height);
cairo_set_source_surface(cr, image, 350, 200);
cairo_paint(cr);
/* Wait for the result of the drawing operation to persist for
the user to see */
sleep(DELAY_IN_SECS);
/* Destroy and release all cairo related contexts */
cairo_destroy(cr);
cairo_surface_destroy(surface);
return 0;
}
Regards,
Victor.
More information about the cairo
mailing list