Re: cairo_paint crashing with 24 bit bpp

Petr Kobalíček <[email protected]>
Newsgroups gmane.comp.lib.cairo
Message-ID <CAB2Z3OdxwPdFFN0z5EZfJKztjLAKfCkdhvXVnUwxNssris8wrw@mail.gmail.com>
Hi, without any further investigation, I think that the problem is that

  CAIRO_FORMAT_RGB24

is actually 32-bit, not 24-bit.

I would start here, hope that helps.

Cheers,
Petr

On Fri, Feb 27, 2015 at 1:22 PM, <[email protected]> wrote:

> 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.
> --
> cairo mailing list
> [email protected]
> http://lists.cairographics.org/mailman/listinfo/cairo

-- 
cairo mailing list
[email protected]
http://lists.cairographics.org/mailman/listinfo/cairo
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.