diff options
-rw-r--r-- | src/regsmi.h | 5 | ||||
-rw-r--r-- | src/smi.h | 36 | ||||
-rw-r--r-- | src/smi501_crtc.c | 189 | ||||
-rw-r--r-- | src/smi_crtc.h | 3 | ||||
-rw-r--r-- | src/smi_driver.c | 12 |
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 @@ -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; |