summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaulo Cesar Pereira de Andrade <pcpa@mandriva.com.br>2008-11-11 15:06:15 -0200
committerPaulo Cesar Pereira de Andrade <pcpa@mandriva.com.br>2008-11-11 15:06:15 -0200
commitcaac648932df69419b8f86c5793a6b33f5997099 (patch)
treea6d5f4e934e1c8dc9319edf4802813d47a7d29fc
parent61dd360a30c8e530185bc71b134c287ab1cdde2c (diff)
Implement an argb cursor using the alpha layer.
The code is <hash>ifdef'ed out by <hash>if SMI_CURSOR_ALPHA_PLANE because the smi 502 hardware is buggy, but it appears to have worked for some older hardware revisions (by looking at code available at ftp.siliconmotion.com.tw). Keeping it at least for now, as it serves as a simple way to reproduce the problems described in smi.h.
-rw-r--r--src/regsmi.h5
-rw-r--r--src/smi.h36
-rw-r--r--src/smi501_crtc.c189
-rw-r--r--src/smi_crtc.h3
-rw-r--r--src/smi_driver.c12
5 files changed, 224 insertions, 21 deletions
diff --git a/src/regsmi.h b/src/regsmi.h
index 35344c3..031e448 100644
--- a/src/regsmi.h
+++ b/src/regsmi.h
@@ -304,6 +304,11 @@ VGAOUT8(SMIPtr pSmi, int port, CARD8 data)
#define SMI501_MAX_CURSOR 64
#define SMILYNX_CURSOR_SIZE 1024
#define SMI501_CURSOR_SIZE 2048
+#if SMI_CURSOR_ALPHA_PLANE
+/* Stored in either 4:4:4:4 or 5:6:5 format */
+# define SMI501_ARGB_CURSOR_SIZE \
+ (SMI501_MAX_CURSOR * SMI501_MAX_CURSOR * 2)
+#endif
/* HWCursor definitons for Panel AND CRT */
#define SMI501_MASK_HWCENABLE 0x80000000
diff --git a/src/smi.h b/src/smi.h
index eb88b48..66d28df 100644
--- a/src/smi.h
+++ b/src/smi.h
@@ -72,6 +72,42 @@ authorization from the XFree86 Project and Silicon Motion.
#define SMI_USE_VIDEO 1
#define SMI_USE_CAPTURE 1
+/*
+ * Leaving attempt implementation of an argb cursor using alpha plane
+ * for the smi 501/502 under this ifdef for now. Maybe it will be fixed
+ * in a subsequent hardware revision.
+ * The problem is that the alpha plane will only work (that is, become
+ * visible) if alpha_plane_tl is set to top:=0 and left:=0.
+ * Also, if alpha_plane_br does not match panel dimensions, the alpha
+ * plane will be displayed tilled in the "first" row, with corruption on
+ * on all odd columns.
+ * Since setting the alpha fb_address works, to implement an argb cursor
+ * using the alpha plane, with the current hardware bugs, it would be
+ * required to:
+ * o allocate an offscreen area of pSmi->lcdWidth * pSmi->lcdHeight * 2
+ * o set statically tl/tr to 0,0,pSmi->lcdWidth-1,pSmi->lcdHeight-1
+ * o use alpha format 3 (argb 4:4:4:4), or alternatively format 1
+ * (rgb 5:6:5), and in the last case, a global 50% alpha is the
+ * best bet, and for the argb cursors being used at the time of this
+ * writing, they look correct, while 100% opaque looks wrong.
+ * o when positioning the pointer, first erase it from the offscreen
+ * area, then repaint it at the proper offset in the alpha offscreen
+ * area.
+ * .... argb software cursor works way better
+ * (There are some other alternatives, like using 8 bits indexed mode,
+ * but when using a global alpha value, instead of per pixel, most argb
+ * cursors will not look correctly, regardless of the alpha value, that
+ * should be from 50 to 100% transparency).
+ * But still there would be the problem of memory requiring a 128 bit
+ * alignment, what would require either moving the image in the memory,
+ * and/or some trick with the vsync pixel panning.
+ *
+ * Until the alpha layer is corrected in some newer revision (or removed?),
+ * it could be used as something like an alternate crt, that happens to be
+ * on top of the panel (and has 16 transparency levels).
+ */
+#define SMI_CURSOR_ALPHA_PLANE 0
+
/******************************************************************************/
/* S T R U C T U R E S */
/******************************************************************************/
diff --git a/src/smi501_crtc.c b/src/smi501_crtc.c
index 565b67a..9e896b1 100644
--- a/src/smi501_crtc.c
+++ b/src/smi501_crtc.c
@@ -372,23 +372,49 @@ SMI501_CrtcSetCursorPosition(xf86CrtcPtr crtc, int x, int y)
{
ScrnInfoPtr pScrn = crtc->scrn;
SMIPtr pSmi = SMIPTR(pScrn);
- xf86CrtcConfigPtr crtcConf = XF86_CRTC_CONFIG_PTR(pScrn);
+ xf86CrtcConfigPtr crtcConf;
+#if SMI_CURSOR_ALPHA_PLANE
+ SMICrtcPrivatePtr smi_crtc = SMICRTC(crtc);
+ MSOCRegPtr mode;
+#endif
int32_t port, offset;
ENTER();
- if (x >= 0)
- offset = x & SMI501_MASK_MAXBITS;
- else
- offset = (-x & SMI501_MASK_MAXBITS) | SMI501_MASK_BOUNDARY;
+#if SMI_CURSOR_ALPHA_PLANE
+ if (smi_crtc->argb_cursor) {
+ mode = pSmi->mode;
+
+ /* uncomment next line if you want to see it rendering the cursor */
+ /* x = y = 0; */
- if (y >= 0)
- offset |= (y & SMI501_MASK_MAXBITS) << 16;
+ mode->alpha_plane_tl.f.left = x;
+ mode->alpha_plane_tl.f.top = y;
+
+ mode->alpha_plane_br.f.right = x + SMI501_CURSOR_SIZE - 1;
+ mode->alpha_plane_br.f.bottom = y + SMI501_CURSOR_SIZE - 1;
+
+ WRITE_SCR(pSmi, ALPHA_PLANE_TL, mode->alpha_plane_tl.value);
+ WRITE_SCR(pSmi, ALPHA_PLANE_BR, mode->alpha_plane_br.value);
+ }
else
- offset |= ((-y & SMI501_MASK_MAXBITS) | SMI501_MASK_BOUNDARY) << 16;
+#endif
+ {
+ crtcConf = XF86_CRTC_CONFIG_PTR(pScrn);
+
+ if (x >= 0)
+ offset = x & SMI501_MASK_MAXBITS;
+ else
+ offset = (-x & SMI501_MASK_MAXBITS) | SMI501_MASK_BOUNDARY;
- port = crtc == crtcConf->crtc[0] ? 0x00f4 : 0x0234;
- WRITE_DCR(pSmi, port, offset);
+ if (y >= 0)
+ offset |= (y & SMI501_MASK_MAXBITS) << 16;
+ else
+ offset |= ((-y & SMI501_MASK_MAXBITS) | SMI501_MASK_BOUNDARY) << 16;
+
+ port = crtc == crtcConf->crtc[0] ? 0x00f4 : 0x0234;
+ WRITE_DCR(pSmi, port, offset);
+ }
LEAVE();
}
@@ -398,15 +424,32 @@ SMI501_CrtcShowCursor(xf86CrtcPtr crtc)
{
ScrnInfoPtr pScrn = crtc->scrn;
SMIPtr pSmi = SMIPTR(pScrn);
- xf86CrtcConfigPtr crtcConf = XF86_CRTC_CONFIG_PTR(pScrn);
+ xf86CrtcConfigPtr crtcConf;
+#if SMI_CURSOR_ALPHA_PLANE
+ SMICrtcPrivatePtr smi_crtc = SMICRTC(crtc);
+ MSOCRegPtr mode;
+#endif
int32_t port, value;
ENTER();
- port = crtc == crtcConf->crtc[0] ? 0x00f0 : 0x0230;
- value = READ_DCR(pSmi, port);
- value |= SMI501_MASK_HWCENABLE;
- WRITE_DCR(pSmi, port, value);
+#if SMI_CURSOR_ALPHA_PLANE
+ if (smi_crtc->argb_cursor) {
+ mode = pSmi->mode;
+
+ mode->alpha_display_ctl.f.enable = 1;
+ WRITE_SCR(pSmi, ALPHA_DISPLAY_CTL, mode->alpha_display_ctl.value);
+ }
+ else
+#endif
+ {
+ crtcConf = XF86_CRTC_CONFIG_PTR(pScrn);
+
+ port = crtc == crtcConf->crtc[0] ? 0x00f0 : 0x0230;
+ value = READ_DCR(pSmi, port);
+ value |= SMI501_MASK_HWCENABLE;
+ WRITE_DCR(pSmi, port, value);
+ }
LEAVE();
}
@@ -416,15 +459,32 @@ SMI501_CrtcHideCursor(xf86CrtcPtr crtc)
{
ScrnInfoPtr pScrn = crtc->scrn;
SMIPtr pSmi = SMIPTR(pScrn);
- xf86CrtcConfigPtr crtcConf = XF86_CRTC_CONFIG_PTR(pScrn);
+ xf86CrtcConfigPtr crtcConf;
+#if SMI_CURSOR_ALPHA_PLANE
+ SMICrtcPrivatePtr smi_crtc = SMICRTC(crtc);
+ MSOCRegPtr mode;
+#endif
int32_t port, value;
ENTER();
- port = crtc == crtcConf->crtc[0] ? 0x00f0 : 0x0230;
- value = READ_DCR(pSmi, port);
- value &= ~SMI501_MASK_HWCENABLE;
- WRITE_DCR(pSmi, port, value);
+#if SMI_CURSOR_ALPHA_PLANE
+ if (smi_crtc->argb_cursor) {
+ mode = pSmi->mode;
+
+ mode->alpha_display_ctl.f.enable = 0;
+ WRITE_SCR(pSmi, ALPHA_DISPLAY_CTL, mode->alpha_display_ctl.value);
+ }
+ else
+#endif
+ {
+ crtcConf = XF86_CRTC_CONFIG_PTR(pScrn);
+
+ port = crtc == crtcConf->crtc[0] ? 0x00f0 : 0x0230;
+ value = READ_DCR(pSmi, port);
+ value &= ~SMI501_MASK_HWCENABLE;
+ WRITE_DCR(pSmi, port, value);
+ }
LEAVE();
}
@@ -434,6 +494,9 @@ SMI501_CrtcLoadCursorImage(xf86CrtcPtr crtc, CARD8 *image)
{
ScrnInfoPtr pScrn = crtc->scrn;
SMIPtr pSmi = SMIPTR(pScrn);
+#if SMI_CURSOR_ALPHA_PLANE
+ SMICrtcPrivatePtr smi_crtc = SMICRTC(crtc);
+#endif
xf86CrtcConfigPtr crtcConf = XF86_CRTC_CONFIG_PTR(pScrn);
int32_t port, value;
@@ -445,10 +508,92 @@ SMI501_CrtcLoadCursorImage(xf86CrtcPtr crtc, CARD8 *image)
memcpy(pSmi->FBBase + value, image,
/* FIXME 1024, but then, should not be using 64x64 cursors */
(SMI501_MAX_CURSOR >> 2) * SMI501_MAX_CURSOR);
+#if SMI_CURSOR_ALPHA_PLANE
+ smi_crtc->argb_cursor = FALSE;
+#endif
LEAVE();
}
+#if SMI_CURSOR_ALPHA_PLANE
+static void
+SMI501_CrtcLoadCursorArgb(xf86CrtcPtr crtc, CARD32 *image)
+{
+ ScrnInfoPtr pScrn = crtc->scrn;
+ SMIPtr pSmi = SMIPTR(pScrn);
+ SMICrtcPrivatePtr smi_crtc = SMICRTC(crtc);
+ MSOCRegPtr mode = pSmi->mode;
+ int16_t *framebuffer;
+ int32_t x, y, bits;
+ int32_t format;
+
+ ENTER();
+
+#define ALPHA_RGB_565 1
+#define ALPHA_ARGB_4444 3
+
+ /* select alpha format */
+ mode->alpha_display_ctl.f.format = ALPHA_ARGB_4444;
+
+ /* 0: use per pixel alpha value 1: use alpha value specified in alpha */
+ if (mode->alpha_display_ctl.f.format == ALPHA_RGB_565) {
+ mode->alpha_display_ctl.f.select = 1;
+ /* 0 to 15, with 0 being transparent and 15 opaque */
+ mode->alpha_display_ctl.f.alpha = 7;
+ }
+ else {
+ /* use per pixel alpha */
+ mode->alpha_display_ctl.f.select = 0;
+ }
+
+ /* alpha layer buffer */
+ mode->alpha_fb_address.value = 0;
+ mode->alpha_fb_address.f.address = pSmi->FBCursorOffset >> 4;
+
+ /* more clearly: width = (SMI501_MAX_CURSOR << 1) >> 4
+ * as the structure is matching the register spec, where it says
+ * the first 4 bits are hardwired to zero */
+ mode->alpha_fb_width.f.offset = SMI501_MAX_CURSOR >> 3;
+ mode->alpha_fb_width.f.width = SMI501_MAX_CURSOR >> 3;
+
+ mode->alpha_chroma_key.f.value = 0;
+ mode->alpha_chroma_key.f.mask = 0;
+ /* enable chroma key */
+ mode->alpha_display_ctl.f.chromakey = 1;
+
+ framebuffer = (int16_t *)(pSmi->FBBase + pSmi->FBCursorOffset);
+ if (mode->alpha_display_ctl.f.format == ALPHA_RGB_565) {
+ /* convert image to rgb 5:6:5 */
+ for (y = 0; y < SMI501_MAX_CURSOR; y++) {
+ for (x = 0; x < SMI501_MAX_CURSOR; x++) {
+ bits = image[y * SMI501_MAX_CURSOR + x];
+ framebuffer[y * SMI501_MAX_CURSOR + x] =
+ (((bits & 0xf80000) >> 8) |
+ ((bits & 0x00fc00) >> 5) |
+ ((bits & 0x0000f8) >> 3));
+ }
+ }
+ }
+ else {
+ /* convert image to argb 4:4:4:4 */
+ for (y = 0; y < SMI501_MAX_CURSOR; y++) {
+ for (x = 0; x < SMI501_MAX_CURSOR; x++) {
+ bits = image[y * SMI501_MAX_CURSOR + x];
+ framebuffer[y * SMI501_MAX_CURSOR + x] =
+ (((bits & 0xf0000000) >> 16) |
+ ((bits & 0x00f00000) >> 12) |
+ ((bits & 0x0000f000) >> 8) |
+ ((bits & 0x000000f0) >> 4));
+ }
+ }
+ }
+ SMI501_WriteMode_alpha(pScrn, mode);
+ smi_crtc->argb_cursor = TRUE;
+
+ LEAVE();
+ }
+#endif
+
static xf86CrtcFuncsRec SMI501_Crtc0Funcs;
static SMICrtcPrivateRec SMI501_Crtc0Priv;
static xf86CrtcFuncsRec SMI501_Crtc1Funcs;
@@ -475,6 +620,10 @@ SMI501_CrtcPreInit(ScrnInfoPtr pScrn)
SMI501_Crtc0Funcs.show_cursor = SMI501_CrtcShowCursor;
SMI501_Crtc0Funcs.hide_cursor = SMI501_CrtcHideCursor;
SMI501_Crtc0Funcs.load_cursor_image = SMI501_CrtcLoadCursorImage;
+#if SMI_CURSOR_ALPHA_PLANE
+ if (!pSmi->Dualhead)
+ SMI501_Crtc0Funcs.load_cursor_argb = SMI501_CrtcLoadCursorArgb;
+#endif
}
crtc0 = xf86CrtcCreate(pScrn, &SMI501_Crtc0Funcs);
diff --git a/src/smi_crtc.h b/src/smi_crtc.h
index 1726255..fcd8345 100644
--- a/src/smi_crtc.h
+++ b/src/smi_crtc.h
@@ -38,6 +38,9 @@ typedef struct {
/* Load the LUT fields above to the hardware */
void (*load_lut)(xf86CrtcPtr crtc);
+#if SMI_CURSOR_ALPHA_PLANE
+ Bool argb_cursor;
+#endif
} SMICrtcPrivateRec, *SMICrtcPrivatePtr;
#define SMICRTC(crtc) ((SMICrtcPrivatePtr)(crtc)->driver_private)
diff --git a/src/smi_driver.c b/src/smi_driver.c
index f9a3258..d4a7afd 100644
--- a/src/smi_driver.c
+++ b/src/smi_driver.c
@@ -1487,10 +1487,16 @@ SMI_MapMem(ScrnInfoPtr pScrn)
"Logical frame buffer at %p - %p\n", pSmi->FBBase,
pSmi->FBBase + pSmi->videoRAMBytes - 1);
- if (IS_MSOC(pSmi))
+ if (IS_MSOC(pSmi)) {
/* Reserve space for panel cursr, and crt if in dual head mode */
+#if SMI_CURSOR_ALPHA_PLANE
+ pSmi->FBReserved = pSmi->FBCursorOffset = pSmi->videoRAMBytes -
+ (pSmi->Dualhead ? SMI501_CURSOR_SIZE << 1 : SMI501_ARGB_CURSOR_SIZE);
+#else
pSmi->FBReserved = pSmi->FBCursorOffset = pSmi->videoRAMBytes -
(pSmi->Dualhead ? SMI501_CURSOR_SIZE << 1 : SMI501_CURSOR_SIZE);
+#endif
+ }
else {
/* Set up offset to hwcursor memory area, at the end of
* the frame buffer.
@@ -1730,6 +1736,10 @@ SMI_ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
size = SMI501_MAX_CURSOR;
flags = (HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1 |
HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK);
+#if SMI_CURSOR_ALPHA_PLANE
+ if (!pSmi->Dualhead)
+ flags |= HARDWARE_CURSOR_ARGB;
+#endif
}
else {
size = SMILYNX_MAX_CURSOR;