8 bit colour palette information


23 posts
by valtonia » Wed Jul 18, 2012 9:46 pm
As part of my ongoing OS development (read: playtime) I've been messing around with the framebuffer and all of the graphicy goodness that comes with it. So far I've developed things like plotting a pixel, drawing lines and circles etc.
I've also got this working in 32/24/16 and 8 bit colour modes. The multi-byte colour modes are relatively straight forward; 32 bpp is 10 bits each BGR with the top 2 bits (I assume) being used for alpha or something. 24 bpp is 8 bits each BGR, and 16 bpp is 5 bits each RGB with bit 0 ignored.
The one thing that was puzzling me though was the 8 bit colour mode. It didn't seem to fall into any discernible pattern of RGB. Following some experimentation I found that white was represented by the value 0xD7 (215). Huh? After some more experimenting and searching the 'net I discovered that the 8 bit colour palette is 216-colours, which are also web-safe colours!

This article confirmed my suspicions and inspired me to write the following function:

http://www.codeproject.com/Articles/7124/Image-Bit-depth-conversion-from-32-Bit-to-8-Bit

Code: Select all
#define STANDARD_PALETTE_VAL_DIFF    51

unsigned int get_8bit_colour_index(unsigned int colour_24bit) {
   const unsigned char standard_palette[] = { 0x00, 0x33, 0x66, 0x99, 0xCC, 0xFF };
   unsigned char result[3] = { 0x00, 0x00, 0x00 };

   for (int i = 0; i < 3; i++)
   {
      unsigned char c = colour_24bit & 0x000000FF;
      int pos = c / STANDARD_PALETTE_VAL_DIFF;

      if (c % STANDARD_PALETTE_VAL_DIFF != 0) {
         if (abs(c - standard_palette[pos]) > abs(c - standard_palette[pos + 1])) {
            pos += 1;
         }
      }

      result[i] = pos;
      colour_24bit = (colour_24bit >> 8);
   }

   return (result[0] * 36) + (result[1] * 6) + result[2];
}


What this does is take a standard 24 bit colour number (in BGR remember) and finds it's nearest colour in the 216-colour palette, returning the index position of the colour.

Of course by this point you're probably wondering why you'd use 8 bit colour. Well, it's easy - 1 byte per pixel and, it's fast. Perfect if you're planning on writing arcade style games :mrgreen:

I'll be sharing my framebuffer and graphics code soon, just pm me if you'd like to get your hands on it now.

V.
Posts: 26
Joined: Wed Jul 04, 2012 9:09 pm
by DexOS » Wed Jul 18, 2012 10:04 pm
I think you will find that 32bits is X888 8 bits each RGB and X = 8 bits for alpha 0-255
Batteries not included, Some assembly required.
User avatar
Posts: 860
Joined: Wed May 16, 2012 6:32 pm
by dom » Wed Jul 18, 2012 10:20 pm
DexOS wrote:I think you will find that 32bits is X888 8 bits each RGB and X = 8 bits for alpha 0-255


Yes, and the 16-bit format is 5 bits red, 6 bits green, 5 bits blue.
The 8bpp does default to "web safe" palette, but can also be set. See:
https://github.com/raspberrypi/linux/bl ... m2708_fb.c
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 4011
Joined: Wed Aug 17, 2011 7:41 pm
Location: Cambridge
by valtonia » Wed Jul 18, 2012 10:32 pm
@DexOS

Yes, on further investigation 32bpp is 8Ax8Bx8Gx8R as you say. Good catch.

V.
Posts: 26
Joined: Wed Jul 04, 2012 9:09 pm
by Cycl0ne » Wed Jul 18, 2012 11:02 pm
Little Endian? ;-)

Dexos, how did you activate the hdmi output?
User avatar
Posts: 102
Joined: Mon Jun 25, 2012 8:03 am
by DexOS » Thu Jul 19, 2012 12:25 pm
Cycl0ne wrote:Little Endian? ;-)

Dexos, how did you activate the hdmi output?

In what way?, if you can output to composite video, you can output to hdmi.
There's no special setup for hdmi compared to composite, from a coding point of view.
I am going to post some of my tuts for bare bones, hoping by tomorrow.
Just want to make sure they are easy for beginners to understand.
Batteries not included, Some assembly required.
User avatar
Posts: 860
Joined: Wed May 16, 2012 6:32 pm
by gidoca » Sat Jul 21, 2012 8:45 pm
DexOS wrote:I am going to post some of my tuts for bare bones, hoping by tomorrow.
Just want to make sure they are easy for beginners to understand.

Great, looking forward to it.
Posts: 6
Joined: Thu Nov 24, 2011 3:56 pm
by DexOS » Sat Jul 21, 2012 9:21 pm
gidoca wrote:
DexOS wrote:I am going to post some of my tuts for bare bones, hoping by tomorrow.
Just want to make sure they are easy for beginners to understand.

Great, looking forward to it.

See here: viewtopic.php?f=72&t=11966
Batteries not included, Some assembly required.
User avatar
Posts: 860
Joined: Wed May 16, 2012 6:32 pm
by -rst- » Sat Nov 24, 2012 9:25 pm
dom wrote:Yes, and the 16-bit format is 5 bits red, 6 bits green, 5 bits blue.
The 8bpp does default to "web safe" palette, but can also be set. See:
https://github.com/raspberrypi/linux/bl ... m2708_fb.c


Hmm, that seems to be driver code, so not directly accessible by user-mode applications? Or have I missed a way to access this...

The framebuffer ioctl method does not seem to work on RPi - my code:

Code: Select all
#include <linux/fb.h>
...
  fbfd = open("/dev/fb0", O_RDWR);
...
  if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) {
    printf("Error reading variable information.\n");
    close(fbfd);
    return(3);
  }
  printf("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel );

  // Get palette information
  unsigned short r[256];
  unsigned short g[256];
  unsigned short b[256];
  unsigned short a[256];
  memset(r, 0xff, 256 * sizeof(unsigned short));
  memset(g, 0xff, 256 * sizeof(unsigned short));
  memset(b, 0xff, 256 * sizeof(unsigned short));
  memset(a, 0xff, 256 * sizeof(unsigned short));
  struct fb_cmap cmap;
  cmap.start = 0;
  cmap.len = 256;
  cmap.red = r;
  cmap.green = g;
  cmap.blue = b;
  cmap.transp = a;
  if (ioctl(fbfd, FBIOGETCMAP, &cmap)) {
    printf("Error reading palette.\n");
    close(fbfd);
    return(4);
  }
...

Succeeds to print out the resolution and bit depth, but always fails to read the palette (regardless of the mode set using 'fbset -depth x').

Does anybody know any other ways to access the driver (to set the palette)?

Thanks,

JP
http://raspberrycompote.blogspot.com/ - Low-level graphics and 'Coding Gold Dust'
Posts: 898
Joined: Thu Nov 01, 2012 12:12 pm
Location: Dublin, Ireland
by valtonia » Sun Nov 25, 2012 10:27 pm
I think you're asking this in the wrong forum - as this is a bare metal forum I doubt that people here will have much experience with the Linux kernel driver.

I've been away from RPi development for a while due to work pressure (I do have to earn a living writing code as well as playing with the RPi - unfortunately!), but just before my hiatus I'd switched over to using the newer interface for the framebuffer, which allows you to set your own palette directly.

I'll post up my code for doing this in the next couple of days. I've got to get my head back into the game I've been away for so long.

A.
Posts: 26
Joined: Wed Jul 04, 2012 9:09 pm
by -rst- » Mon Nov 26, 2012 10:42 am
Thanks for your reply! Same problem here with dedicated RPi time...

Yep, I found this thread using the search and did realise this was in the Bare Metal forum only after having submitted the post. However, Dom's post I quote is about the Linux driver isn't it?

Anyway guess it would be best move the discussion branch into Graphics Programming... here http://www.raspberrypi.org/phpBB3/viewtopic.php?f=67&t=23869

Regs,

JP
http://raspberrycompote.blogspot.com/ - Low-level graphics and 'Coding Gold Dust'
Posts: 898
Joined: Thu Nov 01, 2012 12:12 pm
Location: Dublin, Ireland
by -rst- » Mon Nov 26, 2012 6:03 pm
Btw, doesn't the 'RGB to Websafe palette index' boil down to this:

Code: Select all
int rgb2websafe_index(int r, int g, int b) {
   return 36 * (r / 51) + 6 * (g / 51) + (b / 51);
}

(http://en.wikipedia.org/wiki/Web_colors#Color_table)

;)
http://raspberrycompote.blogspot.com/ - Low-level graphics and 'Coding Gold Dust'
Posts: 898
Joined: Thu Nov 01, 2012 12:12 pm
Location: Dublin, Ireland
by valtonia » Thu Nov 29, 2012 11:32 pm
Yeah, pretty much - if you look at the function I posted early on in this thread you'll see the last(ish) line is really just that same code you mention.
The rest of the function is for converting a full 24-bit colour to its nearest 8-bit web safe equivalent. The reason I did that was because my graphics library can work in all bit depths and I wanted to be able to use the same colour palette for all modes.
Posts: 26
Joined: Wed Jul 04, 2012 9:09 pm
by -rst- » Sat Dec 01, 2012 10:06 pm
valtonia wrote:...I'd switched over to using the newer interface for the framebuffer, which allows you to set your own palette directly.

I'll post up my code for doing this in the next couple of days. I've got to get my head back into the game I've been away for so long.

A.


Howdy, any chance of that code or a pointer for the 'newer interface'?? Can't seem to come up with suitable keywords for Google - swamped with anything nut usable slush...

Thanks,

JP
http://raspberrycompote.blogspot.com/ - Low-level graphics and 'Coding Gold Dust'
Posts: 898
Joined: Thu Nov 01, 2012 12:12 pm
Location: Dublin, Ireland
by jojopi » Sat Dec 01, 2012 11:33 pm
Does anyone else find that 8bit looks blurry compared to other depths?

With overscan disabled on both Pi and display, an alternating black-white vertical pattern is completely sharp in 16bit. In 8bit mode it is just blurred grey.

If I increase or decrease the horizontal framebuffer resolution by 1, then it is sharp in the middle but still blurry at both edges. As if the framebuffer were offset half a pixel horizontally.
User avatar
Posts: 2016
Joined: Tue Oct 11, 2011 8:38 pm
by -rst- » Sat Dec 01, 2012 11:48 pm
I haven't got quite that far yet, but have noticed in 16bpp mode also that some vertical lines are thinner - display resolution vs monitor native res, I guess?

Btw, seems the FBIOPUTCMAP works, even when GET fails...
http://raspberrycompote.blogspot.com/ - Low-level graphics and 'Coding Gold Dust'
Posts: 898
Joined: Thu Nov 01, 2012 12:12 pm
Location: Dublin, Ireland
by valtonia » Mon Dec 03, 2012 10:40 pm
Hey -rst-, here ya go!

First, check out the mailbox i/f documentation: https://github.com/raspberrypi/firmware ... -interface

This is the code I'm using (at least, enough of it that should be useful to you):

Code: Select all
#define BCM2708_PERI_BASE        0x20000000

#define GPUCORE_MAILBOX                   (BCM2708_PERI_BASE + 0xB880)
#define GPUCORE_MAILBOX0                  (BCM2708_PERI_BASE + 0xB880)
#define GPUCORE_MAILBOX1                  (BCM2708_PERI_BASE + 0xB8A0)

#define GPUCORE_MAILBOX_READ_REGISTER     0x00
#define GPUCORE_MAILBOX_WRITE_REGISTER    0x20
#define GPUCORE_MAILBOX_STATUS_REGISTER   0x18
#define GPUCORE_MAILBOX_CONFIG_REGISTER   0x1C

#define MAILBOX_STATUS_FULL               0x80000000
#define MAILBOX_STATUS_EMPTY              0x40000000

#define MAILBOX_CHANNEL_ARM_TO_VC      8
#define MAILBOX_CHANNEL_VC_TO_ARM      9

#define VCTAG_NONE                  0
#define VCTAG_SINGLE                sizeof(vc_mailbox_tag)
#define VCTAG_DOUBLE                (sizeof(vc_mailbox_tag) + sizeof(unsigned int))
#define VCTAG_SINGLE_VAL            sizeof(unsigned int)
#define VCTAG_DOUBLE_VAL            (2 * sizeof(unsigned int))

#define VCTAG_REQUEST               0x00000000
#define VCTAG_RESPONSE              0x00000001

#define VCBUF_PROCESS_REQUEST       0x00000000
#define VCBUF_REQUEST_SUCCESS       0x80000000
#define VCBUF_REQUEST_ERROR         0x80000001

#define VCTAG_GET_FIRMWARE_VERSION  0x00000001
#define VCTAG_GET_BOARD_MODEL       0x00010001
#define VCTAG_GET_BOARD_REVISION    0x00010002
#define VCTAG_GET_BOARD_MAC_ADDRESS 0x00010003
#define VCTAG_GET_BOARD_SERIAL      0x00010004
#define VCTAG_GET_ARM_MEMORY        0x00010005
#define VCTAG_GET_VC_MEMORY         0x00010006
#define VCTAG_GET_CLOCKS            0x00010007
#define VCTAG_GET_COMMAND_LINE      0x00050001
#define VCTAG_GET_DMA_CHANNELS      0x00060001
#define VCTAG_GET_POWER_STATE       0x00020001
#define VCTAG_GET_TIMING            0x00020002
#define VCTAG_SET_POWER_STATE       0x00028001
#define VCTAG_GET_CLOCK_STATE       0x00030001
#define VGTAG_SET_CLOCK_STATE       0x00038001
#define VCTAG_GET_CLOCK_RATE        0x00030002
#define VCTAG_SET_CLOCK_RATE        0x00038002
#define VCTAG_ALLOCATE_FRAMEBUFFER  0x00040001
#define VCTAG_RELEASE_FRAMEBUFFER   0x00048001
#define VCTAG_BLANK_SCREEN          0x00040002
#define VCTAG_FB_GET_DIMENSIONS     0x00040003
#define VCTAG_FB_SET_DIMENSIONS     0x00048003
#define VCTAG_FB_TEST_DIMENSIONS    0x00044003
#define VCTAG_FB_GET_VDIMENSIONS    0x00040004
#define VCTAG_FB_TEST_VDIMENSIONS   0x00044004
#define VCTAG_FB_SET_VDIMENSIONS    0x00048004
#define VCTAG_FB_GET_DEPTH          0x00040005
#define VCTAG_FB_TEST_DEPTH         0x00044005
#define VCTAG_FB_SET_DEPTH          0x00048005
#define VCTAG_FB_GET_PIXEL_ORDER    0x00040006
#define VCTAG_FB_TEST_PIXEL_ORDER   0x00044006
#define VCTAG_FB_SET_PIXEL_ORDER    0x00048006
#define VCTAG_FB_GET_ALPHA_MODE     0x00040007
#define VCTAG_FB_TEST_ALPHA_MODE    0x00044007
#define VCTAG_FB_SET_ALPHA_MODE     0x00048007
#define VCTAG_FB_GET_PITCH          0x00040008
#define VCTAG_FB_GET_VOFFSET        0x00040009
#define VCTAG_FB_TEST_VOFFSET       0x00044009
#define VCTAG_FB_SET_VOFFSET        0x00048009
#define VCTAG_FB_GET_OVERSCAN       0x0004000A
#define VCTAG_FB_TEST_OVERSCAN      0x0004400A
#define VCTAG_FB_SET_OVERSCAN       0x0004800A
#define VCTAG_FB_GET_PALETTE        0x0004000B
#define VCTAG_FB_TEST_PALETTE       0x0004400B
#define VCTAG_FB_SET_PALETTE        0x0004800B

#define ALPHA_MODE_ENABLE           0
#define ALPHA_MODE_REVERSE          1
#define ALPHA_MODE_DISABLE          2

// rgb variant
unsigned int ws_palette_8bit[] = {
   0, 216,
   0x00000000, 0x00330000, 0x00660000, 0x00990000, 0x00CC0000, 0x00FF0000,
   0x00003300, 0x00333300, 0x00663300, 0x00993300, 0x00CC3300, 0x00FF3300,
   0x00006600, 0x00336600, 0x00666600, 0x00996600, 0x00CC6600, 0x00FF6600,
   0x00009900, 0x00339900, 0x00669900, 0x00999900, 0x00CC9900, 0x00FF9900,
   0x0000CC00, 0x0033CC00, 0x0066CC00, 0x0099CC00, 0x00CCCC00, 0x00FFCC00,
   0x0000FF00, 0x0033FF00, 0x0066FF00, 0x0099FF00, 0x00CCFF00, 0x00FFFF00,
   0x00000033, 0x00330033, 0x00660033, 0x00990033, 0x00CC0033, 0x00FF0033,
   0x00003333, 0x00333333, 0x00663333, 0x00993333, 0x00CC3333, 0x00FF3333,
   0x00006633, 0x00336633, 0x00666633, 0x00996633, 0x00CC6633, 0x00FF6633,
   0x00009933, 0x00339933, 0x00669933, 0x00999933, 0x00CC9933, 0x00FF9933,
   0x0000CC33, 0x0033CC33, 0x0066CC33, 0x0099CC33, 0x00CCCC33, 0x00FFCC33,
   0x0000FF33, 0x0033FF33, 0x0066FF33, 0x0099FF33, 0x00CCFF33, 0x00FFFF33,
   0x00000066, 0x00330066, 0x00660066, 0x00990066, 0x00CC0066, 0x00FF0066,
   0x00003366, 0x00333366, 0x00663366, 0x00993366, 0x00CC3366, 0x00FF3366,
   0x00006666, 0x00336666, 0x00666666, 0x00996666, 0x00CC6666, 0x00FF6666,
   0x00009966, 0x00339966, 0x00669966, 0x00999966, 0x00CC9966, 0x00FF9966,
   0x0000CC66, 0x0033CC66, 0x0066CC66, 0x0099CC66, 0x00CCCC66, 0x00FFCC66,
   0x0000FF66, 0x0033FF66, 0x0066FF66, 0x0099FF66, 0x00CCFF66, 0x00FFFF66,
   0x00000099, 0x00330099, 0x00660099, 0x00990099, 0x00CC0099, 0x00FF0099,
   0x00003399, 0x00333399, 0x00663399, 0x00993399, 0x00CC3399, 0x00FF3399,
   0x00006699, 0x00336699, 0x00666699, 0x00996699, 0x00CC6699, 0x00FF6699,
   0x00009999, 0x00339999, 0x00669999, 0x00999999, 0x00CC9999, 0x00FF9999,
   0x0000CC99, 0x0033CC99, 0x0066CC99, 0x0099CC99, 0x00CCCC99, 0x00FFCC99,
   0x0000FF99, 0x0033FF99, 0x0066FF99, 0x0099FF99, 0x00CCFF99, 0x00FFFF99,
   0x000000CC, 0x003300CC, 0x006600CC, 0x009900CC, 0x00CC00CC, 0x00FF00CC,
   0x000033CC, 0x003333CC, 0x006633CC, 0x009933CC, 0x00CC33CC, 0x00FF33CC,
   0x000066CC, 0x003366CC, 0x006666CC, 0x009966CC, 0x00CC66CC, 0x00FF66CC,
   0x000099CC, 0x003399CC, 0x006699CC, 0x009999CC, 0x00CC99CC, 0x00FF99CC,
   0x0000CCCC, 0x0033CCCC, 0x0066CCCC, 0x0099CCCC, 0x00CCCCCC, 0x00FFCCCC,
   0x0000FFCC, 0x0033FFCC, 0x0066FFCC, 0x0099FFCC, 0x00CCFFCC, 0x00FFFFCC,
   0x000000FF, 0x003300FF, 0x006600FF, 0x009900FF, 0x00CC00FF, 0x00FF00FF,
   0x000033FF, 0x003333FF, 0x006633FF, 0x009933FF, 0x00CC33FF, 0x00FF33FF,
   0x000066FF, 0x003366FF, 0x006666FF, 0x009966FF, 0x00CC66FF, 0x00FF66FF,
   0x000099FF, 0x003399FF, 0x006699FF, 0x009999FF, 0x00CC99FF, 0x00FF99FF,
   0x0000CCFF, 0x0033CCFF, 0x0066CCFF, 0x0099CCFF, 0x00CCCCFF, 0x00FFCCFF,
   0x0000FFFF, 0x0033FFFF, 0x0066FFFF, 0x0099FFFF, 0x00CCFFFF, 0x00FFFFFF,
};

typedef struct vc_mailbox_tag {
   unsigned int id;
   unsigned int value_buffer_size;
   union {
      struct {
         unsigned int value_length  : 31;
         unsigned int type          : 1;     // 0 = request, 1 = response
      } bits;
      unsigned int word;
   } ctrl;
   unsigned int value_buffer;     // The first (of possibly many) values
} vc_mailbox_tag;

typedef struct vc_mailbox_hdr {
   unsigned int size;            // Size in bytes including header, end tag and padding
   unsigned int type;            // requests: 0x0 = process request, responses: 0x80000000 = success, 0x80000001 = error
} vc_mailbox_hdr;

typedef struct vc_mailbox_ftr {
   unsigned int end_tag;         // always 0x00000000
   unsigned char padding;
} vc_mailbox_ftr;


unsigned int* mb_make_tag(unsigned char *buf, unsigned int *offset, unsigned int tag_id, unsigned int tagbuf_size, unsigned int tagval_size, unsigned int *data)
{
   vc_mailbox_tag *tag = (vc_mailbox_tag *)(buf + *offset);
   unsigned int *valptr = (unsigned int *)&tag->value_buffer;

   tag->id = tag_id;
   tag->value_buffer_size = tagbuf_size;
   tag->ctrl.bits.value_length = tagval_size;
   tag->ctrl.bits.type = VCTAG_REQUEST;

   for (unsigned int i = 0; i < (tagval_size / sizeof(unsigned int)); i++)
   {
      *(valptr + i) = *data++;
   }

   *offset += sizeof(vc_mailbox_tag) + (tagbuf_size - sizeof(unsigned int));
   return valptr;
}


unsigned int mb_single_request(unsigned int tag, unsigned int arg)
{
   // This is a 1 tag/one value request
   unsigned int tags_size = 0;
   tags_size += VCTAG_SINGLE;

   unsigned int buffer_size = sizeof(vc_mailbox_hdr) + sizeof(vc_mailbox_ftr) + tags_size;
   unsigned char *vc_mailbox_buf = (unsigned char *)malloc(buffer_size);

   vc_mailbox_hdr *hdr = (vc_mailbox_hdr *)vc_mailbox_buf;
   vc_mailbox_ftr *ftr = (vc_mailbox_ftr *)(vc_mailbox_buf + sizeof(vc_mailbox_hdr) + tags_size);

   hdr->size = buffer_size;
   hdr->type = VCBUF_PROCESS_REQUEST;
   ftr->end_tag = 0x00000000;

   unsigned int offset = sizeof(vc_mailbox_hdr);
   unsigned int *valptr = mb_make_tag(vc_mailbox_buf, &offset, tag, VCTAG_SINGLE_VAL, VCTAG_SINGLE_VAL, &arg);

   mbox_write_gen(MAILBOX_CHANNEL_ARM_TO_VC, arm_to_vc((void *)vc_mailbox_buf));
   mbox_read_gen(MAILBOX_CHANNEL_ARM_TO_VC);

   unsigned int response = *valptr;

   free(vc_mailbox_buf);
   return response;
}

unsigned int get_fb_depth(void)
{
   return mb_single_request(VCTAG_FB_GET_DEPTH, 0);
}

unsigned int get_fb_pitch(void)
{
   return mb_single_request(VCTAG_FB_GET_PITCH, 0);
}

void initialise_framebuffer(unsigned int xsize, unsigned ysize, unsigned int bpp, unsigned int *base_addr, unsigned int *size)
{
   // This is a 6 tag/multi value request
   unsigned int tags_size = 0;
   tags_size += VCTAG_SINGLE;    // set alpha mode
   tags_size += VCTAG_DOUBLE;    // set dimensions
   tags_size += VCTAG_DOUBLE;    // set vdimensions
   tags_size += VCTAG_SINGLE;    // set depth
   tags_size += VCTAG_SINGLE;    // set pixel order
   tags_size += VCTAG_DOUBLE;    // set voffset
   tags_size += VCTAG_DOUBLE;    // allocate buffer

   unsigned int buffer_size = sizeof(vc_mailbox_hdr) + sizeof(vc_mailbox_ftr) + tags_size;
   unsigned char *vc_mailbox_buf = (unsigned char *)malloc(buffer_size);

   vc_mailbox_hdr *hdr = (vc_mailbox_hdr *)vc_mailbox_buf;
   vc_mailbox_ftr *ftr = (vc_mailbox_ftr *)(vc_mailbox_buf + sizeof(vc_mailbox_hdr) + tags_size);

   hdr->size = buffer_size;
   hdr->type = VCBUF_PROCESS_REQUEST;
   ftr->end_tag = 0x00000000;

   unsigned int offset = sizeof(vc_mailbox_hdr);

   unsigned int alpha_mode = ALPHA_MODE_DISABLE;
   mb_make_tag(vc_mailbox_buf, &offset, VCTAG_FB_SET_ALPHA_MODE, VCTAG_SINGLE_VAL, VCTAG_SINGLE_VAL, &alpha_mode);

   unsigned int fbdims[2] = { xsize, ysize };
   mb_make_tag(vc_mailbox_buf, &offset, VCTAG_FB_SET_DIMENSIONS, VCTAG_DOUBLE_VAL, VCTAG_DOUBLE_VAL, fbdims);

   unsigned int vfbdims[2] = { xsize, ysize * 3 };
   mb_make_tag(vc_mailbox_buf, &offset, VCTAG_FB_SET_VDIMENSIONS, VCTAG_DOUBLE_VAL, VCTAG_DOUBLE_VAL, vfbdims);

   mb_make_tag(vc_mailbox_buf, &offset, VCTAG_FB_SET_DEPTH, VCTAG_SINGLE_VAL, VCTAG_SINGLE_VAL, &bpp);

   unsigned int pixel_order = 0;
   mb_make_tag(vc_mailbox_buf, &offset, VCTAG_FB_SET_PIXEL_ORDER, VCTAG_SINGLE_VAL, VCTAG_SINGLE_VAL, &pixel_order);

   unsigned int voffset[2] = { 0, 0 };
   mb_make_tag(vc_mailbox_buf, &offset, VCTAG_FB_SET_VOFFSET, VCTAG_DOUBLE_VAL, VCTAG_DOUBLE_VAL, voffset);

   unsigned int fbalign = 0x20;
   unsigned int *valptr = mb_make_tag(vc_mailbox_buf, &offset, VCTAG_ALLOCATE_FRAMEBUFFER, VCTAG_DOUBLE_VAL, VCTAG_SINGLE_VAL, &fbalign);

   mbox_write_gen(MAILBOX_CHANNEL_ARM_TO_VC, arm_to_vc((void *)vc_mailbox_buf));
   mbox_read_gen(MAILBOX_CHANNEL_ARM_TO_VC);

   // Get the base address and fb size (assuming tags are returned in the same order)
   *base_addr = *valptr;
   *size = *(valptr + 1);

   free(vc_mailbox_buf);
   return;
}

void set_palette(void)
{
   // This is a 1 tag/one value request
   unsigned int tags_size = 0;
   tags_size += VCTAG_SINGLE;
   tags_size += (257 * sizeof(unsigned int));

   unsigned int buffer_size = sizeof(vc_mailbox_hdr) + sizeof(vc_mailbox_ftr) + tags_size;
   unsigned char *vc_mailbox_buf = (unsigned char *)malloc(buffer_size);

   vc_mailbox_hdr *hdr = (vc_mailbox_hdr *)vc_mailbox_buf;
   vc_mailbox_ftr *ftr = (vc_mailbox_ftr *)(vc_mailbox_buf + sizeof(vc_mailbox_hdr) + tags_size);

   hdr->size = buffer_size;
   hdr->type = VCBUF_PROCESS_REQUEST;
   ftr->end_tag = 0x00000000;

   unsigned int offset = sizeof(vc_mailbox_hdr);
   unsigned int bufsize = sizeof(ws_palette_8bit) * sizeof(unsigned int);
   unsigned int *valptr = mb_make_tag(vc_mailbox_buf, &offset, VCTAG_FB_SET_PALETTE, bufsize, bufsize, ws_palette_8bit);

   mbox_write_gen(MAILBOX_CHANNEL_ARM_TO_VC, arm_to_vc((void *)vc_mailbox_buf));
   mbox_read_gen(MAILBOX_CHANNEL_ARM_TO_VC);

   free(vc_mailbox_buf);
   return;
}

unsigned int read_mm_reg32(unsigned int base, unsigned int reg)
{
   memory_barrier(); //Make sure we read the right thing
   return *(volatile unsigned int *)(base + reg);
}

void write_mm_reg32(unsigned int base, unsigned int reg, unsigned int value)
{
   *(volatile unsigned int *)(base + reg) = value;
   memory_barrier(); //Make sure the write is visible elsewhere (see read_mm_reg32 for note on how necessary this is)
}

unsigned int mbox_read_gen(unsigned int channel)
{
   unsigned int r = 0;

   do
   {
      while (read_mm_reg32(GPUCORE_MAILBOX, GPUCORE_MAILBOX_STATUS_REGISTER) & MAILBOX_STATUS_EMPTY); // wait for data
      r = read_mm_reg32(GPUCORE_MAILBOX, GPUCORE_MAILBOX_READ_REGISTER); // read the data
   } while ((r & 0xF) != channel); // loop until we received something from the frame buffer channel

   return r & 0xFFFFFFF0;
}

void mbox_write_gen(unsigned int channel, unsigned int v)
{
   while (read_mm_reg32(GPUCORE_MAILBOX, GPUCORE_MAILBOX_STATUS_REGISTER) & MAILBOX_STATUS_FULL);
   write_mm_reg32(GPUCORE_MAILBOX, GPUCORE_MAILBOX_WRITE_REGISTER, channel | (v & 0xFFFFFFF0));
}



Hopefully this will get you going in the right direction.

Please: no flames about using native types - I have no intention of ever porting this code to another platform! :twisted:
Posts: 26
Joined: Wed Jul 04, 2012 9:09 pm
by -rst- » Wed Dec 05, 2012 12:14 pm
Thanks valtonia!

Did you by any chance test this with dispmanx resources?

Not sure if you spotted my other thread (viewtopic.php?f=67&t=23869&p=225627#p225627): I managed to set the (framebuffer) palette using the 'traditional' ioctl approach, but the palette did not apply to the dispmanx resources (only when directly drawing to mmap'ed fb) ...I have suspicion this is just not available (https://github.com/raspberrypi/firmware ... nt-8189176) :(

I'll have a go with this anyway...
http://raspberrycompote.blogspot.com/ - Low-level graphics and 'Coding Gold Dust'
Posts: 898
Joined: Thu Nov 01, 2012 12:12 pm
Location: Dublin, Ireland
by -rst- » Fri Dec 07, 2012 11:28 am
Uh, might have done with the implementation of memory_barrier() and arm_to_vc(...), but maybe I can figure these out... :?
http://raspberrycompote.blogspot.com/ - Low-level graphics and 'Coding Gold Dust'
Posts: 898
Joined: Thu Nov 01, 2012 12:12 pm
Location: Dublin, Ireland
by valtonia » Fri Dec 07, 2012 11:04 pm
Here's arm_to_vc

Code: Select all
unsigned int arm_to_vc(void *p)
{
   return ((unsigned int)p) + 0xC0000000;
}


The memory barrier function is just the standard one you can find floating around all over this forum, usually in asm. The one I used is by dwelch.

Code: Select all
memory_barrier:
   mcr p15, 0, ip, c7, c5, 0        @ invalidate I cache
   mcr p15, 0, ip, c7, c5, 6        @ invalidate BTB
   mcr p15, 0, ip, c7, c10, 4       @ drain write buffer
   mcr p15, 0, ip, c7, c5, 4        @ prefetch flush
   mov pc, lr
Posts: 26
Joined: Wed Jul 04, 2012 9:09 pm
by -rst- » Sun Dec 09, 2012 7:21 pm
Thanks again, valtonia!

Actually I had managed to find that memory barrier code and was somewhat sure the answer to asm_to_vc would be in the peripheral pdf section 1.2.3 "The bus addresses for RAM are set up to map onto the uncached1 bus address range on the VideoCore starting at 0xC0000000.", but always good to get a confirmation :D

I implemented the memory barrier in C code as:

Code: Select all
void memory_barrier() {
  __asm__ ("mcr   p15, 0, ip, c7, c5, 0\n\t"
      "mcr   p15, 0, ip, c7, c5, 6\n\t"
      "mcr   p15, 0, ip, c7, c10, 4\n\t"
      "mcr   p15, 0, ip, c7, c5, 4\n\t"
      "mov   pc, lr");
}


...seems it has to be executed using sudo to avoid 'Illegal instruction' error...
http://raspberrycompote.blogspot.com/ - Low-level graphics and 'Coding Gold Dust'
Posts: 898
Joined: Thu Nov 01, 2012 12:12 pm
Location: Dublin, Ireland
by -rst- » Tue Dec 11, 2012 2:48 pm
Tracked down the 'default memory barrier' used in for example the framebuffer driver to this:

https://github.com/raspberrypi/linux/bl ... m/system.h

#define dmb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" \
: : "r" (0) : "memory")

...replacing my code with that get me a bit further... to a segmentation fault :oops:

Now I start to question whether I am on the right tracks at all: is the mailbox interface even supposed to work from the user space code or am I maybe using a wrong base address for the asm_to_vc (is user vs kernel conversion needed)?

Any help much appreciated,

JP
http://raspberrycompote.blogspot.com/ - Low-level graphics and 'Coding Gold Dust'
Posts: 898
Joined: Thu Nov 01, 2012 12:12 pm
Location: Dublin, Ireland
by -rst- » Tue Dec 18, 2012 11:21 am
DOH :oops: Of course the answer is mmap in Linux... yep, wrong sub-forum, but thought this had be concluded and I blame the one who mentioned the Linux driver :mrgreen:
http://raspberrycompote.blogspot.com/ - Low-level graphics and 'Coding Gold Dust'
Posts: 898
Joined: Thu Nov 01, 2012 12:12 pm
Location: Dublin, Ireland