Commit 06ae9b68 authored by Siarhei Siamashka's avatar Siarhei Siamashka
Browse files

Add support for hardware ARGB cursors up to 32x32 size



Actually they are converted to 32x32 with 256 color palette. In the
case if we have more than 256 unique colors, the color components
of the pixels are reduced from 8-bit to 7-bit, then to 6-bit if
necessary and so on (until we reduce the number of unique colors
so that they can fit the palette). In the worst case we may
theoretically end up with just 2 bits per A, R, G and B channels,
but in practice 7 or 6 bits seem to be enough.
Signed-off-by: default avatarSiarhei Siamashka <siarhei.siamashka@gmail.com>
parent 0ab0a9e8
......@@ -153,7 +153,7 @@ int sunxi_disp_close(sunxi_disp_t *ctx)
* four 32-bit ARGB entries in the palette. *
*****************************************************************************/
int sunxi_hw_cursor_load_pixeldata(sunxi_disp_t *ctx, uint8_t pixeldata[1024])
int sunxi_hw_cursor_load_64x64x2bpp(sunxi_disp_t *ctx, uint8_t pixeldata[1024])
{
uint32_t tmp[4];
__disp_hwc_pattern_t hwc;
......@@ -164,13 +164,24 @@ int sunxi_hw_cursor_load_pixeldata(sunxi_disp_t *ctx, uint8_t pixeldata[1024])
return ioctl(ctx->fd_disp, DISP_CMD_HWC_SET_FB, &tmp);
}
int sunxi_hw_cursor_load_palette(sunxi_disp_t *ctx, uint32_t palette[4])
int sunxi_hw_cursor_load_32x32x8bpp(sunxi_disp_t *ctx, uint8_t pixeldata[1024])
{
uint32_t tmp[4];
__disp_hwc_pattern_t hwc;
hwc.addr = (uintptr_t)&pixeldata[0];
hwc.pat_mode = DISP_HWC_MOD_H32_V32_8BPP;
tmp[0] = ctx->fb_id;
tmp[1] = (uintptr_t)&hwc;
return ioctl(ctx->fd_disp, DISP_CMD_HWC_SET_FB, &tmp);
}
int sunxi_hw_cursor_load_palette(sunxi_disp_t *ctx, uint32_t *palette, int n)
{
uint32_t tmp[4];
tmp[0] = ctx->fb_id;
tmp[1] = (uintptr_t)&palette[0];
tmp[1] = (uintptr_t)palette;
tmp[2] = 0;
tmp[3] = 4 * sizeof(uint32_t);
tmp[3] = n * sizeof(uint32_t);
return ioctl(ctx->fd_disp, DISP_CMD_HWC_SET_PALETTE_TABLE, &tmp);
}
......
......@@ -57,8 +57,9 @@ int sunxi_disp_close(sunxi_disp_t *ctx);
* Support for hardware cursor, which has 64x64 size, 2 bits per pixel,
* four 32-bit ARGB entries in the palette.
*/
int sunxi_hw_cursor_load_pixeldata(sunxi_disp_t *ctx, uint8_t pixeldata[1024]);
int sunxi_hw_cursor_load_palette(sunxi_disp_t *ctx, uint32_t palette[4]);
int sunxi_hw_cursor_load_64x64x2bpp(sunxi_disp_t *ctx, uint8_t pixeldata[1024]);
int sunxi_hw_cursor_load_32x32x8bpp(sunxi_disp_t *ctx, uint8_t pixeldata[1024]);
int sunxi_hw_cursor_load_palette(sunxi_disp_t *ctx, uint32_t *palette, int n);
int sunxi_hw_cursor_set_position(sunxi_disp_t *ctx, int x, int y);
int sunxi_hw_cursor_show(sunxi_disp_t *ctx);
int sunxi_hw_cursor_hide(sunxi_disp_t *ctx);
......
......@@ -27,11 +27,14 @@
#include "xf86.h"
#include "xf86Cursor.h"
#include "cursorstr.h"
#include "sunxi_disp_hwcursor.h"
#include "sunxi_disp.h"
#include "fbdev_priv.h"
#include "uthash.h"
static void ShowCursor(ScrnInfoPtr pScrn)
{
sunxi_disp_t *disp = SUNXI_DISP(pScrn);
......@@ -54,14 +57,14 @@ static void SetCursorColors(ScrnInfoPtr pScrn, int bg, int fg)
{
sunxi_disp_t *disp = SUNXI_DISP(pScrn);
uint32_t palette[4] = { 0, 0, bg | 0xFF000000, fg | 0xFF000000 };
sunxi_hw_cursor_load_palette(disp, &palette[0]);
sunxi_hw_cursor_load_palette(disp, &palette[0], 4);
}
static void LoadCursorImage(ScrnInfoPtr pScrn, unsigned char *bits)
{
SunxiDispHardwareCursor *private = SUNXI_DISP_HWC(pScrn);
sunxi_disp_t *disp = SUNXI_DISP(pScrn);
sunxi_hw_cursor_load_pixeldata(disp, bits);
sunxi_hw_cursor_load_64x64x2bpp(disp, bits);
if (private->EnableHWCursor)
(*private->EnableHWCursor) (pScrn);
}
......@@ -70,13 +73,84 @@ static Bool UseHWCursorARGB(ScreenPtr pScreen, CursorPtr pCurs)
{
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
SunxiDispHardwareCursor *private = SUNXI_DISP_HWC(pScrn);
/* We support ARGB cursors up to 32x32 */
if (pCurs->bits->height <= 32 && pCurs->bits->width <= 32) {
if (private->EnableHWCursor)
(*private->EnableHWCursor) (pScrn);
return TRUE;
}
if (private->DisableHWCursor)
(*private->DisableHWCursor) (pScrn);
return FALSE;
}
typedef struct {
uint32_t color;
UT_hash_handle hh;
} hashed_color;
static inline uint32_t quantize_color(uint32_t color, int keepbits)
{
uint32_t bitmask = 0x01010101 * ((1 << (8 - keepbits)) - 1);
color &= ~bitmask;
color |= (color >> keepbits) & bitmask;
return color;
}
static void LoadCursorARGB(ScrnInfoPtr pScrn, CursorPtr pCurs)
{
sunxi_disp_t *disp = SUNXI_DISP(pScrn);
int width = pCurs->bits->width;
int height = pCurs->bits->height;
int keepbits, colors_count;
uint8_t *cursor_image = calloc(32 * 32, 1);
uint32_t *palette = malloc(256 * sizeof(uint32_t));
hashed_color *colors_array = malloc(width * height * sizeof(hashed_color));
/* Reduce the number of bits per color until we can fit into 8-bit palette */
for (keepbits = 8; keepbits > 0; keepbits--) {
int x, y;
uint32_t *argb = (uint32_t *)pCurs->bits->argb;
hashed_color *hash = NULL;
hashed_color *hc;
/* Always have transparent color at palette index 0 */
hc = &colors_array[0];
hc->color = 0;
palette[0] = 0;
colors_count = 1;
HASH_ADD_INT(hash, color, hc);
/* Generate the rest of the palette */
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
uint32_t color = quantize_color(*argb++, keepbits);
HASH_FIND_INT(hash, &color, hc);
if (hc == NULL) {
if (colors_count < 256)
palette[colors_count] = color;
hc = &colors_array[colors_count++];
hc->color = color;
HASH_ADD_INT(hash, color, hc);
}
cursor_image[y * 32 + x] = hc - colors_array;
}
}
HASH_CLEAR(hh, hash);
if (colors_count <= 256)
break;
}
sunxi_hw_cursor_load_palette(disp, palette, colors_count);
sunxi_hw_cursor_load_32x32x8bpp(disp, cursor_image);
free(colors_array);
free(cursor_image);
free(palette);
}
SunxiDispHardwareCursor *SunxiDispHardwareCursor_Init(ScreenPtr pScreen)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment