2015-08-23 11 views
2

Я пишу крошечную библиотеку для взаимодействия с абстракцией фреймбуфера Linux. Все мои графические карты используют один и тот же формат пикселей (один октет на канал, четыре канала, заказ BGRA), поэтому до сих пор библиотека просто принимает этот формат. Однако API-интерфейс framebuffer предоставляет данные формата пикселей, которые я должен использовать, если я хочу, чтобы библиотека работала с любым фреймбуфером Linux. Вам не нужно знать, как работает фреймбуфер, чтобы ответить на этот вопрос (я надеюсь), просто немного ворчание, с которым я не владею. Вот информация пиксельного формата содержится в моих заголовках:Linux framebuffer pixel bitfield общая реализация

/* Interpretation of offset for color fields: All offsets are from the right, 
* inside a "pixel" value, which is exactly 'bits_per_pixel' wide (means: you 
* can use the offset as right argument to <<). A pixel afterwards is a bit 
* stream and is written to video memory as that unmodified. 
* 
* For pseudocolor: offset and length should be the same for all color 
* components. Offset specifies the position of the least significant bit 
* of the pallette index in a pixel value. Length indicates the number 
* of available palette entries (i.e. # of entries = 1 << length). 
*/ 
struct fb_bitfield { 
     __u32 offset;     /* beginning of bitfield  */ 
     __u32 length;     /* length of bitfield   */ 
     __u32 msb_right;    /* != 0 : Most significant bit is */ 
             /* right */ 
}; 

/* snip */ 

struct fb_var_screeninfo { 
    /* snip */ 

     __u32 bits_per_pixel;   /* guess what     */ 
     __u32 grayscale;    /* 0 = color, 1 = grayscale, */ 
             /* >1 = FOURCC     */ 
     struct fb_bitfield red;   /* bitfield in fb mem if true color, */ 
     struct fb_bitfield green;  /* else only length is significant */ 
     struct fb_bitfield blue; 
     struct fb_bitfield transp;  /* transparency     */  

     __u32 nonstd;     /* != 0 Non standard pixel format */ 

    /* snip */ 
}; 

Мне нужно написать пиксель отформатированный с помощью данной информации в массив символов из четырех символов (R, G, B и A). В ошибочных попытках я сделал, чтобы сделать это выглядеть следующим образом:

long pxl = 0; 
/* downsample each channel to the length (assuming its less than 8 bits) */ 
/* with a right-shift, then left shift it over into place */ 
/* haven't done anything with fb_bitfield.msb_right */ 
pxl |= (r >> (8 - vinfo.red.length)) << vinfo.red.offset; 
pxl |= (g >> (8 - vinfo.green.length)) << vinfo.green.offset; 
pxl |= (b >> (8 - vinfo.blue.length)) << vinfo.blue.offset; 
pxl |= (a >> (8 - vinfo.transp.length)) << vinfo.transp.offset; 
fb[xy2off(x, y)] = /* umm... */; 
/* little endian, big endian? Can I just assign here? */ 

xy2off преобразует координаты в индекс. fb - указатель на фреймбуфер (с отображением памяти).

Может ли кто-нибудь указать мне в правильном направлении для преобразования и назначения этих пикселей? Спасибо :-)

ответ

1

Dear вероятно несуществующие люди ищет ответ на это: вот хак код, который я получил, что, кажется, работает в настоящее время:

void pixel(int x, int y, uint8_t r, uint8_t g, uint8_t b, uint8_t a) 
{ 
    int i; 
    long pxl = 0; 
    pxl |= (r >> (8 - vinfo.red.length)) << vinfo.red.offset; 
    pxl |= (g >> (8 - vinfo.green.length)) << vinfo.green.offset; 
    pxl |= (b >> (8 - vinfo.blue.length)) << vinfo.blue.offset; 
    pxl |= (a >> (8 - vinfo.transp.length)) << vinfo.transp.offset; 
    for (i = 0; i < sizeof(long); i++) { 
     fb[xy2off(x, y) + i] = ((char *)(&pxl))[i]; 
    } 
}

Отсутствие обработки порядка байт, имея дело с msb_right, или любым своего рода оптимизация.

+0

Будет работать, когда длина = 8. Когда длина> 8, вы правы смещаете отрицательное количество бит, которое является либо UB, либо определенной реализацией, я не помню. Я думаю, вы хотите сделать '(r >> (vinfo.red.length -8))'. Я бы также избегал 'long' и вместо этого использовал' int' или 'int32_t',' unsigned' было бы лучше. – user3528438

+0

И ваш способ сделать 'fb [xy2off (x, y)] =' не очень эффективен. Хороший способ сделать это: '* (uint32_t *) (fb + xy2off (x, y)) = pxl;', тогда вы можете перемещать 4 значения с помощью одной команды, считая, что память правильно выровнена. 'fb' является' char * ', поэтому вы не нарушаете строгое правило сглаживания. – user3528438

+0

Спасибо за совет! Я приму ваш улучшенный ответ, если вы опубликуете его как один – nebuch