summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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;