I've just written mga_dispcurs.c, a software cursor
using G400 command primitives instead of high level X
commands as midispcur.c does.
As I understand it, it is necessary to be able to add
and remove the cursor from the screen with DMA commands
in order to do 3D on the second head. mga_dispcurs.c should
be a good base to start from.
What is left:
Add code to mga_dispcurs.c to save the current position of the
cursor and the current position and size of the saved area
to a memory region accessible by the DRI-module.
Add code to the DRI-module to save and restore the cursorregion
as necessary.
Add code to mga_dri.c so we can initialize two screens on one
device. This, I don't know exactly how to go about I'm afraid.
I should be able to add code to initialize 3D on only the
second head, but I'm not sure I can figure out how to modify
mga_dri.c to initialize 3D on both heads...
I thought it would be best if I sent this report to the list so
someone doesn't duplicate my effort of rewriting midispcur.c.
(Or perhaps I have already duplicated someones work here? :)
regards
Andreas Ehliar
/*
* mga_dispcurs.c
*
* Heavily inspired by midispcur.c
*/
/*
Copyright 2001 Andreas Ehliar
All Rights Reserved.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ANDREAS EHLIAR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "X.h"
#include "misc.h"
#include "input.h"
#include "cursorstr.h"
#include "mipointer.h"
#include "misprite.h"
#include "xf86.h"
#include "xf86Pci.h"
#include "servermd.h"
#include "mga.h"
#include "mga_reg.h"
#include "mga_macros.h"
static Bool mgaDCRealizeCursor(), mgaDCUnrealizeCursor();
static Bool mgaDCPutUpCursor(), mgaDCSaveUnderCursor();
static Bool mgaDCRestoreUnderCursor(), mgaDCMoveCursor();
static Bool mgaDCChangeSave();
static miSpriteCursorFuncRec mgaDCFuncs = {
mgaDCRealizeCursor,
mgaDCUnrealizeCursor,
mgaDCPutUpCursor,
mgaDCSaveUnderCursor,
mgaDCRestoreUnderCursor,
mgaDCMoveCursor,
mgaDCChangeSave,
};
Bool mgaDCInitialize(ScreenPtr pScreen,miPointerScreenFuncPtr screenFuncs)
{
if (!miSpriteInitialize(pScreen,&mgaDCFuncs,screenFuncs)){
xf86DrvMsg(xf86Screens[pScreen->myNum]->scrnIndex,X_ERROR,
"Couldn't initialize software cursor\n");
return FALSE;
}
xf86DrvMsg(xf86Screens[pScreen->myNum]->scrnIndex,X_INFO,
"Initialized custom software cursor\n");
return TRUE;
}
/* Used for converting an image in the device independant bitmap
* format into something we can send to the card */
static int getbyte(unsigned char *src,unsigned char *mask,
unsigned int xbyte,unsigned int y,
unsigned int width,unsigned int height,
unsigned int pitch,
unsigned int invert)
{
unsigned int tmpsrc;
unsigned int tmpmask;
if ( xbyte > width / 8) {
return 0;
}
if ( y >= height ) {
return 0;
}
tmpsrc = *(src+y*pitch+xbyte);
tmpmask = *(mask+y*pitch+xbyte);
if (invert) {
tmpsrc = tmpsrc ^ 0xff;
}
if ( xbyte == width / 8) {
int tempmask = (1 << (width & 0x7)) - 1;
return tmpsrc & tmpmask & tempmask;
}
return tmpsrc & tmpmask;
}
static Bool
mgaDCRealizeCursor (ScreenPtr pScreen, CursorPtr pCursor)
{
return TRUE;
}
/* Upload an image of this cursor if necessary. */
static Bool
mgaDCRealize (ScreenPtr pScreen, CursorPtr pCursor)
{
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
MGAPtr pMga = MGAPTR(pScrn);
unsigned char *cursorbase = pMga->FbBase + pMga->FbCursorOffset;
unsigned char *src = pCursor->bits->source;
unsigned char *mask = pCursor->bits->mask;
int xbyte,y;
int paddedwidth;
if ( pMga->CurrentCursor == pCursor){
/* Cursor already uploaded.
* NOTE: Need to check if the server copies CursorPtrs around
* in memory since this won't work in that case.
* This should work anyway, but with reduced performance */
return TRUE;
}
paddedwidth = BitmapBytePad(pCursor->bits->width);
MGAStormSync ( pScrn );
/* According to the X Protocol specs the components of
the cursor may be transformed arbitrarly to meet display limitations,
so I guess it is technically correct to ignore cursors larger than
64x64 pixels. This could technically fall back to a software fallback
if necessary.
*/
/* Upload the foreground image */
for ( y=0; y<64; y++ ){
for ( xbyte=0; xbyte<64/8; xbyte++ ) {
*cursorbase = getbyte(src,mask,xbyte,y,
pCursor->bits->width,
pCursor->bits->height,
paddedwidth,0);
cursorbase++;
}
}
cursorbase = pMga->FbBase + pMga->FbCursorOffset + 64*64/8;
/* Upload the background image */
for ( y=0; y<64; y++ ){
for ( xbyte=0; xbyte<64/8; xbyte++ ) {
*cursorbase = getbyte(src,mask,xbyte,y,
pCursor->bits->width,
pCursor->bits->height,
paddedwidth,1);
cursorbase++;
}
}
pMga->CurrentCursor = pCursor;
return TRUE;
}
static Bool
mgaDCUnrealizeCursor(ScreenPtr pScreen,CursorPtr pCursor)
{
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
MGAPtr pMga = MGAPTR(pScrn);
if ((pMga->CurrentCursor == pCursor) && (pCursor->bits->refcnt <= 1)){
pMga->CurrentCursor = NULL;
}
return TRUE;
}
static Bool
mgaDCPutUpCursor(ScreenPtr pScreen,
CursorPtr pCursor,
int x,int y,
unsigned long source,
unsigned long mask)
{
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
MGAPtr pMga = MGAPTR(pScrn);
CARD32 tempcol;
CHECK_DMA_QUIESCENT(pMga, pScrn);
mgaDCRealize(pScreen,pCursor);
xf86SetLastScrnFlag(pScrn->entityList[0], pScrn->scrnIndex);
pMga->RestoreAccelState(pScrn);
WAITFIFO(14);
OUTREG(MGAREG_CXBNDRY,((pScrn->virtualX -1)<< 16));
OUTREG(MGAREG_YBOT,pScrn->virtualY * pScrn->displayWidth + pMga->YDstOrg);
/* NOTE: no support for depth of 15 */
/* Set the foreground color of the cursor */
if(pScrn->bitsPerPixel == 16){
tempcol = (((pCursor->foreRed & 0xf800)>>11) << 11) |
(((pCursor->foreGreen & 0xfc00)>>10) << 5) |
(((pCursor->foreBlue & 0xf800)>>11) << 0);
}else{
tempcol = (((pCursor->foreRed & 0xff00)>>8) << 16) |
(((pCursor->foreGreen & 0xff00)>>8) << 8) |
(((pCursor->foreBlue & 0xff00)>>8) << 0);
}
OUTREG(MGAREG_FCOL,tempcol);
/* Pixels are in 1-bit format */
/* And blit the cursor to the screen... */
OUTREG(MGAREG_AR3,pMga->FbCursorOffset * 8);
OUTREG(MGAREG_AR0,pMga->FbCursorOffset*8+64*64-1);
OUTREG(MGAREG_FXBNDRY,(x+63) << 16 |
(x & 0xffff));
OUTREG(MGAREG_YDSTLEN,(y << 16) | 64);
OUTREG(MGAREG_DWGCTL + MGAREG_EXEC,
MGADWG_TRANSC |
MGADWG_BMONOLEF |
0xc << 16 |
MGADWG_SHIFTZERO |
MGADWG_SGNZERO |
MGADWG_LINEAR |
MGADWG_RSTR |
MGADWG_BITBLT);
/* Set the background color of the cursor */
if(pScrn->bitsPerPixel == 16){
tempcol = (((pCursor->backRed & 0xf800)>>11) << 11) |
(((pCursor->backGreen & 0xfc00)>>10) << 5) |
(((pCursor->backBlue & 0xf800)>>11) << 0);
}else{
tempcol = (((pCursor->backRed & 0xff00)>>8) << 16) |
(((pCursor->backGreen & 0xff00)>>8) << 8) |
(((pCursor->backBlue & 0xff00)>>8) << 0);
}
/* And blit the cursor to the screen... */
OUTREG(MGAREG_FCOL,tempcol);
OUTREG(MGAREG_AR3,pMga->FbCursorOffset * 8 + 64*64 );
OUTREG(MGAREG_AR0,pMga->FbCursorOffset*8+64*64-1 + 64*64);
OUTREG(MGAREG_FXBNDRY,(x+63) << 16 |
(x & 0xffff));
OUTREG(MGAREG_YDSTLEN,(y << 16) | 64);
OUTREG(MGAREG_DWGCTL + MGAREG_EXEC,
MGADWG_TRANSC |
MGADWG_BMONOLEF |
0xc << 16 |
MGADWG_SHIFTZERO |
MGADWG_SGNZERO |
MGADWG_LINEAR |
MGADWG_RSTR |
MGADWG_BITBLT);
/* FIXME, don't need to restore everything */
pMga->RestoreAccelState(pScrn);
return TRUE;
}
static Bool
mgaDCSaveUnderCursor(ScreenPtr pScreen,
int x, int y,
int w, int h)
{
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
MGAPtr pMga = MGAPTR(pScrn);
/* Not sure what to do with this large a region. */
if ( w > 127 ) {
w = 127;
}
if ( h > 127 ) {
h = 127;
}
/* Clamp the region to the edges of the screen */
if ( x < 0 ) {
w += x;
x = 0;
}
if ( y < 0 ) {
h += y;
y = 0;
}
if ( x + w > pScrn->virtualX) {
w = pScrn->virtualX - x ;
}
if ( y + h > pScrn->virtualY) {
h = pScrn->virtualY - y ;
}
CHECK_DMA_QUIESCENT(pMga, pScrn);
xf86SetLastScrnFlag(pScrn->entityList[0], pScrn->scrnIndex);
pMga->RestoreAccelState(pScrn);
WAITFIFO(8);
OUTREG(MGAREG_PITCH,128*(pScrn->bitsPerPixel/8));
OUTREG(MGAREG_DSTORG,pMga->DstOrg + pMga->FbCursorOffset + 64*64*2/8);
OUTREG(MGAREG_AR0,XYADDRESS(x,y)+w-1);
OUTREG(MGAREG_AR3,XYADDRESS(x,y));
OUTREG(MGAREG_AR5, pMga->CurrentLayout.displayWidth);
OUTREG(MGAREG_FXBNDRY,(w-1)<<16);
OUTREG(MGAREG_YDSTLEN,(0 << 16) | h);
OUTREG(MGAREG_DWGCTL+MGAREG_EXEC,
MGADWG_RSTR |
MGADWG_BFCOL |
0xc<<16 |
MGADWG_SHIFTZERO |
MGADWG_SGNZERO |
MGADWG_BITBLT);
pMga->RestoreAccelState(pScrn);
return TRUE;
}
static Bool
mgaDCRestoreUnderCursor(ScreenPtr pScreen,
int x, int y,
int w, int h)
{
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
MGAPtr pMga = MGAPTR(pScrn);
/* I don't really know what to do once we get this large a
* region */
if ( w > 127 ) {
xf86DrvMsg(pScrn->scrnIndex,X_ERROR,
"Cursor too large\n");
w = 127;
}
if ( h > 127 ) {
xf86DrvMsg(pScrn->scrnIndex,X_ERROR,
"Cursor too large\n");
h = 127;
}
/* Clamp the region to the edges of the screen */
if ( x < 0 ) {
w += x;
x = 0;
}
if ( y < 0 ) {
h += y;
y = 0;
}
if ( x + w > pScrn->virtualX) {
w = pScrn->virtualX - x ;
}
if ( y + h > pScrn->virtualY) {
h = pScrn->virtualY - y ;
}
CHECK_DMA_QUIESCENT(pMga, pScrn);
xf86SetLastScrnFlag(pScrn->entityList[0], pScrn->scrnIndex);
pMga->RestoreAccelState(pScrn);
WAITFIFO(7);
OUTREG(MGAREG_SRCORG,pMga->DstOrg + pMga->FbCursorOffset + 64*64*2/8);
OUTREG(MGAREG_AR0,w-1);
OUTREG(MGAREG_AR3,0);
OUTREG(MGAREG_AR5,pScrn->bitsPerPixel*128/8);
OUTREG(MGAREG_FXBNDRY,((x+w-1)<<16) | x);
OUTREG(MGAREG_YDSTLEN,(y<<16) | h);
OUTREG(MGAREG_DWGCTL+MGAREG_EXEC,
MGADWG_RSTR |
MGADWG_BFCOL |
0xc<<16 |
MGADWG_SHIFTZERO |
MGADWG_SGNZERO |
MGADWG_BITBLT);
pMga->RestoreAccelState(pScrn);
return TRUE;
}
/* Change the position of what we are currently saving of
* the screen. */
static Bool
mgaDCChangeSave(ScreenPtr pScreen,
int x,int y,
int w, int h,
int dx, int dy)
{
mgaDCRestoreUnderCursor(pScreen,x+dx,y+dy,w,h);
mgaDCSaveUnderCursor(pScreen,x,y,w,h);
return TRUE;
}
static Bool
mgaDCMoveCursor(ScreenPtr pScreen, CursorPtr pCursor,
int x, int y,
int w, int h,
int dx, int dy,
unsigned long source, unsigned long mask)
{
/* This could be changed to use the flicker free code as is done
* in midispcur.c, but the card is fast enough and the cursors
* usually small enough that it doesn't matter that much to me. */
mgaDCRealize(pScreen,pCursor);
mgaDCRestoreUnderCursor(pScreen,x,y,w,h);
mgaDCPutUpCursor(pScreen,pCursor,x+dx,y+dy,source,mask);
return TRUE;
}
Index: hw/xfree86/drivers/mga/Imakefile
===================================================================
RCS file: /cvsroot/dri/xc/xc/programs/Xserver/hw/xfree86/drivers/mga/Imakefile,v
retrieving revision 1.12
diff -u -r1.12 Imakefile
--- hw/xfree86/drivers/mga/Imakefile 2001/04/09 21:56:26 1.12
+++ hw/xfree86/drivers/mga/Imakefile 2001/06/12 21:31:21
@@ -57,10 +57,12 @@
MGASRCS = mga_driver.c mga_hwcurs.c /* mga_cmap.c */ mga_dac3026.c mga_dacG.c \
mga_storm8.c mga_storm16.c mga_storm24.c mga_storm32.c mga_arc.c \
- mga_dga.c mga_shadow.c mga_video.c mga_g450pll.c mga_dh.c $(DRISRCS)
+ mga_dga.c mga_shadow.c mga_video.c mga_g450pll.c mga_dh.c $(DRISRCS) \
+ mga_dispcurs.c
MGAOBJS = mga_driver.o mga_hwcurs.o /* mga_cmap.o */ mga_dac3026.o mga_dacG.o \
mga_storm8.o mga_storm16.o mga_storm24.o mga_storm32.o mga_arc.o \
- mga_dga.o mga_shadow.o mga_video.o mga_g450pll.o mga_dh.o $(DRIOBJS)
+ mga_dga.o mga_shadow.o mga_video.o mga_g450pll.o mga_dh.o $(DRIOBJS) \
+ mga_dispcurs.o
SRCS = $(MGASRCS) $(MGAHALSRCS)
OBJS = $(MGAOBJS) $(MGAHALOBJS)
Index: hw/xfree86/drivers/mga/mga.h
===================================================================
RCS file: /cvsroot/dri/xc/xc/programs/Xserver/hw/xfree86/drivers/mga/mga.h,v
retrieving revision 1.20
diff -u -r1.20 mga.h
--- hw/xfree86/drivers/mga/mga.h 2001/05/01 21:39:13 1.20
+++ hw/xfree86/drivers/mga/mga.h 2001/06/12 21:31:21
@@ -350,6 +350,7 @@
int agpMode;
#endif
+ CursorPtr CurrentCursor;
XF86VideoAdaptorPtr adaptor;
Bool SecondCrtc;
GDevPtr device;
@@ -454,6 +455,8 @@
void MGAInitVideo(ScreenPtr pScreen);
void MGAResetVideo(ScrnInfoPtr pScrn);
+
+Bool mgaDCInitialize(ScreenPtr pScreen,miPointerScreenFuncPtr screenFuncs);
#ifdef XF86DRI
Index: hw/xfree86/drivers/mga/mga_driver.c
===================================================================
RCS file: /cvsroot/dri/xc/xc/programs/Xserver/hw/xfree86/drivers/mga/mga_driver.c,v
retrieving revision 1.28
diff -u -r1.28 mga_driver.c
--- hw/xfree86/drivers/mga/mga_driver.c 2001/05/01 21:39:33 1.28
+++ hw/xfree86/drivers/mga/mga_driver.c 2001/06/12 21:31:23
@@ -2260,8 +2260,32 @@
}
}
} else { /* Second CRTC */
+ /* Allocate space for a custom sw-cursor
+ * 128*128 in order to comply with PITCH limitations */
+ int cursorsize = 128*128*(pScrn->bitsPerPixel/8); /* Temporary storage
+area, some extra space for padding */
+ cursorsize += 64*64*2; /* Storage area for the cursor bitmap */
+
pMga->FbUsableSize = pMgaEnt->slaveFbMapSize;
pMga->HWCursor = FALSE;
+ if(pScrn->bitsPerPixel == 16 || pScrn->bitsPerPixel == 32){
+ if( pScrn->virtualY * pScrn->displayWidth *
+ pScrn->bitsPerPixel / 8 <=
+ pMga->FbUsableSize - cursorsize ) {
+
+ pMga->FbUsableSize -= cursorsize;
+
+ pMga->FbCursorOffset =
+ pMgaEnt->slaveFbMapSize -
+ cursorsize;
+ } else {
+ pMga->HWCursor = FALSE;
+ xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
+ "Too little offscreen memory for custom sw cursor; "
+ "using standard SW cursor\n");
+ }
+ }
+
+
}
} else {
pMga->FbUsableSize = pMga->FbMapSize - pMga->YDstOrg * bytesPerPixel;
@@ -3112,7 +3136,11 @@
/* Initialize software cursor.
Must precede creation of the default colormap */
- miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
+ if (pMga->SecondCrtc){
+ mgaDCInitialize(pScreen,xf86GetPointerScreenFuncs());
+ }else{
+ miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
+ }
/* Initialize HW cursor layer.
Must follow software cursor initialization*/
Index: hw/xfree86/loader/misym.c
===================================================================
RCS file: /cvsroot/dri/xc/xc/programs/Xserver/hw/xfree86/loader/misym.c,v
retrieving revision 1.1.1.6
diff -u -r1.1.1.6 misym.c
--- hw/xfree86/loader/misym.c 2000/09/23 21:24:27 1.1.1.6
+++ hw/xfree86/loader/misym.c 2001/06/12 21:31:23
@@ -32,6 +32,7 @@
#include "mipointer.h"
#include "migc.h"
#include "miline.h"
+#include "misprite.h"
#include "mizerarc.h"
#include "mifillarc.h"
#include "micmap.h"
@@ -127,6 +128,7 @@
SYMFUNC(miRecolorCursor)
SYMFUNC(miPointerWarpCursor)
SYMFUNC(miDCInitialize)
+ SYMFUNC(miSpriteInitialize)
SYMFUNC(miRectsToRegion)
SYMFUNC(miPointInRegion)
SYMFUNC(miInverse)