/******************************Module*Header**********************************\ * * ************************** * * DirectDraw SAMPLE CODE * * ************************** * * Module Name: ddvideo.c * * Content: DirectDraw Videoports implementation * * Copyright (c) 1994-1999 3Dlabs Inc. Ltd. All rights reserved. * Copyright (c) 1995-2003 Microsoft Corporation. All rights reserved. \*****************************************************************************/ #include "glint.h" #include "tag.h" //#include #include "dma.h" //@@BEGIN_DDKSPLIT #ifdef W95_DDRAW_VIDEO // Define P3R3DX_VIDEO to allow use of 32bit Macros in ramdac.h #define P3R3DX_VIDEO 1 #include "ramdac.h" #include extern DWORD CALLBACK __VD_AutoflipOverlay ( void ); extern DWORD CALLBACK __VD_AutoupdateOverlay ( void ); #if 0 #define P2_VIDPORT_WIDTH 768 #define P2_VIDPORT_HEIGHT 288 #endif // how many DrawOverlay calls to wait after an UpdateOverlay() // generally 1 #define OVERLAY_UPDATE_WAIT 1 // how many DrawOverlay calls to wait after a SetPosition() // generally 1 #define OVERLAY_SETPOS_WAIT 1 // how many DrawOverlay calls between repaints (0=no repaints) // generally 5-15 #define OVERLAY_CYCLE_WAIT 15 // How many "DrawOverlay calls" a speedy DrawOverlay is worth. // Generally 1 #define OVERLAY_DRAWOVERLAY_SPEED 1 // How many "DrawOverlay calls" a pretty DrawOverlay is worth. // Generally the same as OVERLAY_CYCLE_WAIT, or 1 if it is 0. #define OVERLAY_DRAWOVERLAY_PRETTY 15 // How long in milliseconds to wait for the videoport before timing out. #define OVERLAY_VIDEO_PORT_TIMEOUT 100 static BOOL g_bFlipVideoPortDoingAutoflip = FALSE; //----------------------------------------------------------------------------- // // __VD_PixelOffsetFromMemoryBase // // Calculates the offset from the memory base as the chip sees it. This is // relative to the base address in the chip and is in pixels // //----------------------------------------------------------------------------- long __inline __VD_PixelOffsetFromMemoryBase( P3_THUNKEDDATA* pThisDisplay, LPDDRAWI_DDRAWSURFACE_LCL pLcl) { DWORD lOffset; lOffset = DDSurf_SurfaceOffsetFromMemoryBase(pThisDisplay, pLcl); // Work out pixel offset into the framestore if (DDSurf_BitDepth(pLcl) == 24) { lOffset = lOffset / 3; } else { lOffset = lOffset >> DDSurf_GetPixelShift(pLcl); } return lOffset; } // __VD_PixelOffsetFromMemoryBase // Debug function to dump a video port description #if DBG //----------------------------------------------------------------------------- // // __VD_FillYUVSurface // //----------------------------------------------------------------------------- static void __VD_FillYUVSurface( LPDDRAWI_DDRAWSURFACE_LCL lpLcl, DWORD Value) { BYTE* pCurrentLine = (BYTE*)lpLcl->lpGbl->fpVidMem; WORD x, y; WORD* pSurface; WORD CurrentColor = (WORD)(Value & 0xFFFF); for (y = 0; y < lpLcl->lpGbl->wHeight; y++) { pSurface = (WORD*)pCurrentLine; for (x = 0; x < lpLcl->lpGbl->wWidth; x++) { // YUV Surface is 16Bits *pSurface++ = CurrentColor; } pCurrentLine += lpLcl->lpGbl->lPitch; if ((pCurrentLine - (31 << 1)) <= (BYTE*)pSurface) { while (pSurface++ < (WORD*)pCurrentLine) { *pSurface = 0xFFFF; } } } } // __VD_FillYUVSurface //----------------------------------------------------------------------------- // // __VD_DumpVPDesc // //----------------------------------------------------------------------------- static void __VD_DumpVPDesc( int Level, DDVIDEOPORTDESC vp) { #define CONNECT_REPORT(param) \ if (vp.VideoPortType.dwFlags & DDVPCONNECT_##param) \ { \ DISPDBG((Level, " " #param)); \ } DISPDBG((Level,"Port Size: %d x %d", vp.dwFieldWidth, vp.dwFieldHeight)); DISPDBG((Level,"VBI Width: %d", vp.dwVBIWidth)); DISPDBG((Level,"uS/Field: %d", vp.dwMicrosecondsPerField)); DISPDBG((Level,"Pixels/Sec: %d", vp.dwMaxPixelsPerSecond)); DISPDBG((Level,"Port ID: %d", vp.dwVideoPortID)); DISPDBG((Level,"Flags: ")); CONNECT_REPORT(INTERLACED); CONNECT_REPORT(VACT); CONNECT_REPORT(INVERTPOLARITY); CONNECT_REPORT(DOUBLECLOCK); CONNECT_REPORT(DISCARDSVREFDATA); CONNECT_REPORT(HALFLINE); CONNECT_REPORT(SHAREEVEN); CONNECT_REPORT(SHAREODD); DISPDBG((Level,"Connection GUID:")); if (MATCH_GUID((vp.VideoPortType.guidTypeID), DDVPTYPE_E_HREFH_VREFH)) { DISPDBG((Level, " DDVPTYPE_E_HREFH_VREFH")); } else if (MATCH_GUID((vp.VideoPortType.guidTypeID), DDVPTYPE_E_HREFH_VREFL)) { DISPDBG((Level, " DDVPTYPE_E_HREFH_VREFL")); } else if (MATCH_GUID((vp.VideoPortType.guidTypeID), DDVPTYPE_E_HREFL_VREFH)) { DISPDBG((Level, " DDVPTYPE_E_HREFL_VREFH")); } else if (MATCH_GUID((vp.VideoPortType.guidTypeID), DDVPTYPE_E_HREFL_VREFL)) { DISPDBG((Level, " DDVPTYPE_E_HREFL_VREFL")); } else if (MATCH_GUID((vp.VideoPortType.guidTypeID), DDVPTYPE_CCIR656)) { DISPDBG((Level, " CCIR656")); } else if (MATCH_GUID((vp.VideoPortType.guidTypeID), DDVPTYPE_BROOKTREE)) { DISPDBG((Level, " BROOKTREE")); } else if (MATCH_GUID((vp.VideoPortType.guidTypeID), DDVPTYPE_PHILIPS)) { DISPDBG((Level, " PHILIPS")); } else { DISPDBG((ERRLVL," ERROR: Unknown connection type!")); } } // __VD_DumpVPDesc #define DUMPVPORT(a, b) __VD_DumpVPDesc(a, b); #define FILLYUV(a, c) __VD_FillYUVSurface(a, c); #else #define DUMPVPORT(a, b) #define FILLYUV(a, c) #endif //----------------------------------------------------------------------------- // // __VD_CheckVideoPortStatus // // Checks to see if the videoport seems to be OK. If it is, // we return TRUE. if bWait is set then we hang around and // try to decide if the Video is OK. // //----------------------------------------------------------------------------- #define ERROR_TIMOUT_VP 470000 #define ERROR_TIMOUT_COUNT 50 BOOL __VD_CheckVideoPortStatus( P3_THUNKEDDATA* pThisDisplay, BOOL bWait) { DWORD dwMClock; DWORD dwCurrentLine; DWORD dwCurrentIndex; DWORD dwNewLine; DWORD dwNewMClock; // Is the videoport on? if (!pThisDisplay->VidPort.bActive) return FALSE; // Read the current MClock dwMClock = READ_GLINT_CTRL_REG(MClkCount); if (bWait) pThisDisplay->VidPort.bResetStatus = TRUE; if (pThisDisplay->VidPort.bResetStatus) { dwCurrentLine = READ_GLINT_CTRL_REG(VSACurrentLine); dwCurrentIndex = READ_GLINT_CTRL_REG(VSAVideoAddressIndex); // At start of day, record the MClock time for the start of the line pThisDisplay->VidPort.dwStartLineTime = dwMClock; // Also record the starting line pThisDisplay->VidPort.dwStartLine = dwCurrentLine; pThisDisplay->VidPort.dwStartIndex = dwCurrentIndex; pThisDisplay->VidPort.bResetStatus = FALSE; return TRUE; } if (bWait) { do { // Read the current line dwCurrentLine = READ_GLINT_CTRL_REG(VSACurrentLine); // OK, a line of video should take approx: // 1 Second / 50-60 fields/second / 300 lines = // 0.000066 = 66uS. // If the MClock is running at, say 70Mhz that is 0.000000014 seconds/clock // So a line should take 0.000066 / 0.000000014 MClocks = ~4700 MClocks // Wait for 100 times longer than it should take to draw a line.... do { dwNewMClock = READ_GLINT_CTRL_REG(MClkCount); } while (dwNewMClock < (dwMClock + ERROR_TIMOUT_VP)); dwNewLine = READ_GLINT_CTRL_REG(VSACurrentLine); // Has the line count advanced? if (dwNewLine == dwCurrentLine) { dwCurrentIndex = READ_GLINT_CTRL_REG(VSAVideoAddressIndex); if (dwCurrentIndex == pThisDisplay->VidPort.dwStartIndex) { // Disable the videoport if the error count goes to high pThisDisplay->VidPort.dwErrorCount++; // Reset the status as we need to make sure the timer restarts. pThisDisplay->VidPort.bResetStatus = TRUE; if (pThisDisplay->VidPort.dwErrorCount > ERROR_TIMOUT_COUNT) { DISPDBG((WRNLVL,"StartLine: %d, CurrentLine: %d, StartIndex: %d, CurrentIndex: %d", pThisDisplay->VidPort.dwStartLine, dwCurrentLine, pThisDisplay->VidPort.dwStartIndex, dwCurrentIndex)); DISPDBG((ERRLVL,"ERROR: VideoStream not working!")); pThisDisplay->VidPort.bActive = FALSE; return FALSE; } } else { pThisDisplay->VidPort.dwErrorCount = 0; pThisDisplay->VidPort.bResetStatus = TRUE; } } // If it has flag a reset and break else { pThisDisplay->VidPort.dwErrorCount = 0; pThisDisplay->VidPort.bResetStatus = TRUE; } } while (pThisDisplay->VidPort.dwErrorCount); } else { // Has the line count advanced? if (dwMClock > (pThisDisplay->VidPort.dwStartLineTime + ERROR_TIMOUT_VP)) { dwCurrentLine = READ_GLINT_CTRL_REG(VSACurrentLine); if (pThisDisplay->VidPort.dwStartLine == dwCurrentLine) { dwCurrentIndex = READ_GLINT_CTRL_REG(VSAVideoAddressIndex); if (dwCurrentIndex == pThisDisplay->VidPort.dwStartIndex) { // Disable the videoport if the error count goes to high pThisDisplay->VidPort.dwErrorCount++; DISPDBG((WRNLVL,"ERROR: Timeout at %d", dwMClock)); // Reset the status as we need to make sure the timer restarts. pThisDisplay->VidPort.bResetStatus = TRUE; // Disable the videoport if (pThisDisplay->VidPort.dwErrorCount > ERROR_TIMOUT_COUNT) { DISPDBG((WRNLVL,"StartLine: %d, CurrentLine: %d, StartIndex: %d, CurrentIndex: %d", pThisDisplay->VidPort.dwStartLine, dwCurrentLine, pThisDisplay->VidPort.dwStartIndex, dwCurrentIndex)); DISPDBG((ERRLVL,"ERROR: VideoStream not working!")); pThisDisplay->VidPort.bActive = FALSE; } } else { pThisDisplay->VidPort.dwErrorCount = 0; pThisDisplay->VidPort.bResetStatus = TRUE; } } else { // Reset the error status pThisDisplay->VidPort.dwErrorCount = 0; pThisDisplay->VidPort.bResetStatus = TRUE; } } } return pThisDisplay->VidPort.bActive; } // __VD_CheckVideoPortStatus //----------------------------------------------------------------------------- // // DdUpdateVideoPort // // This required function sets up the video port // //----------------------------------------------------------------------------- DWORD CALLBACK DdUpdateVideoPort ( LPDDHAL_UPDATEVPORTDATA pInput) { DWORD i; P3_THUNKEDDATA* pThisDisplay; DWORD dwCurrentDisplay; DWORD dwLineScale; DWORD dwEnable; DWORD dwDiscard; DWORD XScale = 0; DWORD YScale = 0; VMIREQUEST In; VMIREQUEST Out; DWORD dwSrcPixelWidth; DWORD dwSrcHeight; DWORD dwDstPixelWidth; DWORD dwDstHeight; StreamsRegister_Settings PortSettings; StreamsRegister_VSPartialConfigA VSPartialA; GET_THUNKEDDATA(pThisDisplay, pInput->lpDD->lpGbl); DISPDBG((DBGLVL,"** In DdUpdateVideoPort, dwFlags = %d", pInput->dwFlags)); DUMPVPORT(DBGLVL ,pInput->lpVideoPort->ddvpDesc); pThisDisplay->pGLInfo->dwVSACaughtFrames = 0; pThisDisplay->pGLInfo->dwVSADroppedFrames = 0; pThisDisplay->pGLInfo->dwVSALastDropped = 0; if (pInput->dwFlags == DDRAWI_VPORTSTOP) { DISPDBG((DBGLVL," Stopping VideoPort")); // Stop any autoflipping. if ( pThisDisplay->pGLInfo->dwPeriodVideoVBL != 0 ) { if ( pThisDisplay->pGLInfo->dwVideoEventHandle == (DWORD)NULL ) { DISPDBG((DBGLVL,"** DdUpdateVideoPort - VPORTSTOP - was autoflipping on bogus event handle.")); } pThisDisplay->pGLInfo->dwPeriodVideoVBL = 0; pThisDisplay->pGLInfo->dwCountdownVideoVBL = 0; DISPDBG((DBGLVL,"** DdUpdateVideoPort - VPORTSTOP - autoflipping now disabled.")); } WAIT_GLINT_FIFO(2); pThisDisplay->VidPort.bActive = FALSE; pThisDisplay->VidPort.bResetStatus = TRUE; pThisDisplay->VidPort.dwErrorCount = 0; pThisDisplay->VidPort.lpSurf[0] = NULL; pThisDisplay->VidPort.lpSurf[1] = NULL; pThisDisplay->VidPort.lpSurf[2] = NULL; // Disable the interrupt. dwEnable = READ_GLINT_CTRL_REG(IntEnable); dwEnable &= ~INTR_ENABLE_VIDSTREAM_A; LOAD_GLINT_REG(IntEnable, dwEnable); // Disable the videoport LOAD_GLINT_REG(VSAControl, __PERMEDIA_DISABLE); } else if ((pInput->dwFlags == DDRAWI_VPORTSTART) || (pInput->dwFlags == DDRAWI_VPORTUPDATE)) { DISPDBG((DBGLVL," Starting/Updating VideoPort")); pThisDisplay->VidPort.lpSurf[0] = NULL; pThisDisplay->VidPort.lpSurf[1] = NULL; pThisDisplay->VidPort.lpSurf[2] = NULL; // Videoport only on P2's, therefore much more fifo room WAIT_GLINT_FIFO(100); // Disable the videoport so we can setup a new configuration LOAD_GLINT_REG(VSAControl, __PERMEDIA_DISABLE); // How many surfaces do we have? if (pInput->lpVideoInfo->dwVPFlags & DDVP_AUTOFLIP) { if (pInput->dwNumAutoflip == 0) pThisDisplay->VidPort.dwNumSurfaces = 1; else pThisDisplay->VidPort.dwNumSurfaces = pInput->dwNumAutoflip; DISPDBG((DBGLVL,"Surfaces passed in (AUTOFLIP) = %d", pThisDisplay->VidPort.dwNumSurfaces)); for(i = 0; i < pThisDisplay->VidPort.dwNumSurfaces; i++) { LPDDRAWI_DDRAWSURFACE_LCL pLcl = (pInput->lplpDDSurface[i])->lpLcl; if (pLcl->ddsCaps.dwCaps & DDSCAPS_FRONTBUFFER) { DISPDBG((DBGLVL,"Surface %d is the FRONTBUFFER", i)); dwCurrentDisplay = i; } FILLYUV(pLcl, i * 0x4444); // Store away the offset to this surface pThisDisplay->VidPort.dwSurfacePointer[i] = pLcl->lpGbl->fpVidMem; pThisDisplay->VidPort.lpSurf[i] = pLcl; } // Start or continue any autoflipping. #if DBG if ( pThisDisplay->pGLInfo->dwVideoEventHandle == (DWORD)NULL ) { DISPDBG((DBGLVL,"** DdUpdateVideoPort - trying to autoflipping using bogus event handle.")); } #endif if ( pThisDisplay->pGLInfo->dwPeriodVideoVBL == 0 ) { pThisDisplay->pGLInfo->dwPeriodVideoVBL = OVERLAY_AUTOFLIP_PERIOD; pThisDisplay->pGLInfo->dwCountdownVideoVBL = OVERLAY_AUTOFLIP_PERIOD; DISPDBG((DBGLVL,"** DdUpdateVideoPort - autoflipping now enabled.")); } } else { LPDDRAWI_DDRAWSURFACE_LCL lpNextSurf = (pInput->lplpDDSurface[0])->lpLcl; i = 0; // Stop any autoflipping. if ( pThisDisplay->pGLInfo->dwPeriodVideoVBL != 0 ) { #if DBG if ( pThisDisplay->pGLInfo->dwVideoEventHandle == (DWORD)NULL ) { DISPDBG((DBGLVL,"** DdUpdateVideoPort - was trying to autoflip using bogus event handle.")); } #endif pThisDisplay->pGLInfo->dwPeriodVideoVBL = 0; pThisDisplay->pGLInfo->dwCountdownVideoVBL = 0; DISPDBG((DBGLVL,"** DdUpdateVideoPort - autoflipping now disabled.")); } while (lpNextSurf != NULL) { if (lpNextSurf->ddsCaps.dwCaps & DDSCAPS_FRONTBUFFER) { DISPDBG((DBGLVL,"Surface %d is the FRONTBUFFER", i)); dwCurrentDisplay = i; } // Store away the offset to this surface pThisDisplay->VidPort.dwSurfacePointer[i] = lpNextSurf->lpGbl->fpVidMem; pThisDisplay->VidPort.lpSurf[i] = lpNextSurf; FILLYUV(lpNextSurf, i * 0x4444); // Is there another surface in the chain? if (lpNextSurf->lpAttachList) { lpNextSurf = lpNextSurf->lpAttachList->lpAttached; if (lpNextSurf == NULL) break; } else break; // Have we spun around the loop? if (lpNextSurf == (pInput->lplpDDSurface[0])->lpLcl) break; i++; } pThisDisplay->VidPort.dwNumSurfaces = i + 1; DISPDBG((DBGLVL,"Surfaces passed in (Not AutoFlip) = %d", (i + 1))); } DISPDBG((DBGLVL," Addresses: 0x%x, 0x%x, 0x%x", pThisDisplay->VidPort.dwSurfacePointer[0], pThisDisplay->VidPort.dwSurfacePointer[1], pThisDisplay->VidPort.dwSurfacePointer[2])); // Remember the size of the vertical blanking interval and the size of the frame. pThisDisplay->VidPort.dwFieldWidth = pInput->lpVideoPort->ddvpDesc.dwFieldWidth; pThisDisplay->VidPort.dwFieldHeight = pInput->lpVideoPort->ddvpDesc.dwFieldHeight; // Setup the Host register so that it points to the same surface we will display. pThisDisplay->VidPort.dwCurrentHostFrame = dwCurrentDisplay; dwSrcPixelWidth = (pInput->lpVideoInfo->dwVPFlags & DDVP_CROP) ? (pInput->lpVideoInfo->rCrop.right - pInput->lpVideoInfo->rCrop.left) : pInput->lpVideoPort->ddvpDesc.dwFieldWidth; dwSrcHeight = (pInput->lpVideoInfo->dwVPFlags & DDVP_CROP) ? (pInput->lpVideoInfo->rCrop.bottom - pInput->lpVideoInfo->rCrop.top) : pInput->lpVideoPort->ddvpDesc.dwFieldHeight; DISPDBG((DBGLVL,"Source Width: %d", dwSrcPixelWidth)); DISPDBG((DBGLVL,"Source Height: %d", dwSrcHeight)); // Do we need to prescale the surface? if (pInput->lpVideoInfo->dwVPFlags & DDVP_PRESCALE) { DISPDBG((DBGLVL,"Prescale Width:%d, Height:%d", pInput->lpVideoInfo->dwPrescaleWidth, pInput->lpVideoInfo->dwPrescaleHeight)); if ((pInput->lpVideoInfo->dwPrescaleWidth != 0) && (pInput->lpVideoInfo->dwPrescaleWidth != pInput->lpVideoPort->ddvpDesc.dwFieldWidth)) { XScale = pInput->lpVideoPort->ddvpDesc.dwFieldWidth / pInput->lpVideoInfo->dwPrescaleWidth; switch(XScale) { case 2: XScale = 1; break; case 4: XScale = 2; break; case 8: XScale = 3; break; default: XScale = 0; break; } } if ((pInput->lpVideoInfo->dwPrescaleHeight != 0) && (pInput->lpVideoInfo->dwPrescaleHeight != pInput->lpVideoPort->ddvpDesc.dwFieldHeight)) { YScale = pInput->lpVideoPort->ddvpDesc.dwFieldHeight / pInput->lpVideoInfo->dwPrescaleHeight; switch(YScale) { case 2: YScale = 1; break; case 4: YScale = 2; break; case 8: YScale = 3; break; default: YScale = 0; break; } } // HACK! HACK! dwDstPixelWidth = pInput->lpVideoInfo->dwPrescaleWidth; dwDstHeight = pInput->lpVideoInfo->dwPrescaleHeight; } else { dwDstPixelWidth = dwSrcPixelWidth; dwDstHeight = dwSrcHeight; } DISPDBG((DBGLVL,"Dest Width: %d", dwDstPixelWidth)); DISPDBG((DBGLVL,"Dest Height: %d", dwDstHeight)); // Need to setup the registers differently if we are mirroring top to bottom if (pInput->lpVideoInfo->dwVPFlags & DDVP_MIRRORUPDOWN) { // Make sure we aren't prescaling... if (YScale == 0) { pThisDisplay->VidPort.dwSurfacePointer[0] += (pInput->lplpDDSurface[0])->lpLcl->lpGbl->lPitch * (pInput->lpVideoPort->ddvpDesc.dwFieldHeight); pThisDisplay->VidPort.dwSurfacePointer[1] += (pInput->lplpDDSurface[0])->lpLcl->lpGbl->lPitch * (pInput->lpVideoPort->ddvpDesc.dwFieldHeight); pThisDisplay->VidPort.dwSurfacePointer[2] += (pInput->lplpDDSurface[0])->lpLcl->lpGbl->lPitch * (pInput->lpVideoPort->ddvpDesc.dwFieldHeight); } else { pThisDisplay->VidPort.dwSurfacePointer[0] += (pInput->lplpDDSurface[0])->lpLcl->lpGbl->lPitch * (pInput->lpVideoInfo->dwPrescaleHeight); pThisDisplay->VidPort.dwSurfacePointer[1] += (pInput->lplpDDSurface[0])->lpLcl->lpGbl->lPitch * (pInput->lpVideoInfo->dwPrescaleHeight); pThisDisplay->VidPort.dwSurfacePointer[2] += (pInput->lplpDDSurface[0])->lpLcl->lpGbl->lPitch * (pInput->lpVideoInfo->dwPrescaleHeight); } } if (pInput->lpVideoPort->ddvpDesc.VideoPortType.dwPortWidth == 8) dwLineScale = 0; else dwLineScale = 1; // Setup the configuration of the VideoPort // This is done by a call to the VXD as the registers that are touched have bits // that are shared with the TV Out and the ROM. // *********************** // UnitMode: Typically setup for 8 or 16 bit YUV input port. // GPMode: Not used. // HREF_POL_A: Polarity active of HREF // VREF_POL_A: Polarity active of VREF // VActive: Wether the VACT signal is active high or low (if there is one). // Can be set to the inverse of the HREF as a good guess(?) // UseField: Stream A on or off // FieldPolA: How to treat the field polarity of stream A // FieldEdgeA: // VActiveVBIA: // InterlaceA: Interlaced data on A? // ReverseA: Should we reverse the YUV data on A // *********************** PortSettings.UnitMode = ((pInput->lpVideoPort->ddvpDesc.VideoPortType.dwPortWidth == 8) ? STREAMS_MODE_STREAMA_STREAMB : STREAMS_MODE_STREAMA_WIDE16); In.dwSize = sizeof(VMIREQUEST); In.dwRegister = P2_VSSettings; In.dwCommand = *((DWORD*)(&PortSettings)); In.dwDevNode = pThisDisplay->dwDevNode; In.dwOperation = GLINT_VMI_WRITE; VXDCommand(GLINT_VMI_COMMAND, &In, sizeof(VMIREQUEST), &Out, sizeof(VMIREQUEST)); VSPartialA.HRefPolarityA = ((pThisDisplay->VidPort.dwStreamAFlags & VIDEOPORT_HREF_ACTIVE_HIGH) ? __PERMEDIA_ENABLE : __PERMEDIA_DISABLE); VSPartialA.VRefPolarityA = ((pThisDisplay->VidPort.dwStreamAFlags & VIDEOPORT_VREF_ACTIVE_HIGH) ? __PERMEDIA_ENABLE : __PERMEDIA_DISABLE); // There is no setting in DirectX for the polarity of the active signal. Therefore we must assume one value. This // has been chosen based on the setting that gives the correct effect for a Bt827/829 VSPartialA.VActivePolarityA = __PERMEDIA_ENABLE; VSPartialA.UseFieldA = __PERMEDIA_DISABLE; VSPartialA.FieldPolarityA = ((pInput->lpVideoPort->ddvpDesc.VideoPortType.dwFlags & DDVPCONNECT_INVERTPOLARITY) ? __PERMEDIA_ENABLE : __PERMEDIA_DISABLE); VSPartialA.FieldEdgeA = __PERMEDIA_DISABLE; VSPartialA.VActiveVBIA = __PERMEDIA_DISABLE; VSPartialA.InterlaceA = __PERMEDIA_ENABLE; VSPartialA.ReverseDataA = __PERMEDIA_ENABLE; In.dwSize = sizeof(VMIREQUEST); In.dwRegister = P2_VSAPartialConfig; In.dwCommand = *((DWORD*)(&VSPartialA)); In.dwDevNode = pThisDisplay->dwDevNode; In.dwOperation = GLINT_VMI_WRITE; VXDCommand( GLINT_VMI_COMMAND, &In, sizeof(VMIREQUEST), &Out, sizeof(VMIREQUEST)); // Setup Stream A if (pInput->lpVideoInfo->dwVPFlags & DDVP_SKIPEVENFIELDS) { dwDiscard = PM_VSACONTROL_DISCARD_1; DISPDBG((DBGLVL,"Skipping Even Fields")); } else if(pInput->lpVideoInfo->dwVPFlags & DDVP_SKIPODDFIELDS) { dwDiscard = PM_VSACONTROL_DISCARD_2; DISPDBG((DBGLVL,"Skipping Odd Fields")); } else dwDiscard = __PERMEDIA_DISABLE; LOAD_GLINT_REG(VSAControl, PM_VSACONTROL_VIDEO(__PERMEDIA_ENABLE) | PM_VSACONTROL_VBI(__PERMEDIA_DISABLE) | PM_VSACONTROL_BUFFER((pThisDisplay->VidPort.dwNumSurfaces == 3) ? 1 : 0) | PM_VSACONTROL_SCALEX(XScale) | PM_VSACONTROL_SCALEY(YScale) | PM_VSACONTROL_MIRRORY((pInput->lpVideoInfo->dwVPFlags & DDVP_MIRRORUPDOWN) ? __PERMEDIA_ENABLE : __PERMEDIA_DISABLE) | PM_VSACONTROL_MIRRORX((pInput->lpVideoInfo->dwVPFlags & DDVP_MIRRORLEFTRIGHT) ? __PERMEDIA_ENABLE : __PERMEDIA_DISABLE) | PM_VSACONTROL_DISCARD(dwDiscard) | PM_VSACONTROL_COMBINE((pInput->lpVideoInfo->dwVPFlags & DDVP_INTERLEAVE) ? __PERMEDIA_ENABLE : __PERMEDIA_DISABLE) | PM_VSACONTROL_LOCKTOB(__PERMEDIA_DISABLE)); // Point the register at the surface being used LOAD_GLINT_REG(VSAVideoAddressHost, pThisDisplay->VidPort.dwCurrentHostFrame); // Check on the video stride LOAD_GLINT_REG(VSAVideoStride, (((pInput->lplpDDSurface[0])->lpLcl->lpGbl->lPitch) >> 3)); // Vertical data if (pInput->lpVideoInfo->dwVPFlags & DDVP_CROP) { LOAD_GLINT_REG(VSAVideoStartLine, pInput->lpVideoInfo->rCrop.top); LOAD_GLINT_REG(VSAVideoEndLine, pInput->lpVideoInfo->rCrop.top + dwDstHeight); } else { LOAD_GLINT_REG(VSAVideoStartLine, 0); LOAD_GLINT_REG(VSAVideoEndLine, dwDstHeight); } // Not using VBI, must disable (P2ST may not start up in a fixed state) LOAD_GLINT_REG(VSAVBIAddressHost, 0); LOAD_GLINT_REG(VSAVBIAddressIndex, 0); LOAD_GLINT_REG(VSAVBIAddress0, 0); LOAD_GLINT_REG(VSAVBIAddress1, 0); LOAD_GLINT_REG(VSAVBIAddress2, 0); LOAD_GLINT_REG(VSAVBIStride, 0); LOAD_GLINT_REG(VSAVBIStartLine, 0); LOAD_GLINT_REG(VSAVBIEndLine, 0); LOAD_GLINT_REG(VSAVBIStartData, 0); LOAD_GLINT_REG(VSAVBIEndData, 0); #define CLOCKS_PER_PIXEL 2 // Horizontal data // If the if (pInput->lpVideoPort->ddvpDesc.VideoPortType.dwFlags & DDVPCONNECT_VACT) { // Set StartData and EndData to their limits and // let VACT tell us when we are getting active data. LOAD_GLINT_REG(VSAVideoStartData, 0); LOAD_GLINT_REG(VSAVideoEndData, (VIDEOPORT_MAX_FIELD_WIDTH) - 1); } else { if (pInput->lpVideoInfo->dwVPFlags & DDVP_CROP) { LOAD_GLINT_REG(VSAVideoStartData, (pInput->lpVideoInfo->rCrop.left * CLOCKS_PER_PIXEL)); LOAD_GLINT_REG(VSAVideoEndData, (pInput->lpVideoInfo->rCrop.left * CLOCKS_PER_PIXEL) + ((dwDstPixelWidth / 2) * CLOCKS_PER_PIXEL)); } else { LOAD_GLINT_REG(VSAVideoStartData, 0); LOAD_GLINT_REG(VSAVideoEndData, (dwDstPixelWidth * CLOCKS_PER_PIXEL)); } } // Point at the surfaces LOAD_GLINT_REG(VSAVideoAddress0, ((pThisDisplay->VidPort.dwSurfacePointer[0] - pThisDisplay->dwScreenFlatAddr) >> 3)); LOAD_GLINT_REG(VSAVideoAddress1, ((pThisDisplay->VidPort.dwSurfacePointer[1] - pThisDisplay->dwScreenFlatAddr) >> 3)); LOAD_GLINT_REG(VSAVideoAddress2, ((pThisDisplay->VidPort.dwSurfacePointer[2] - pThisDisplay->dwScreenFlatAddr) >> 3)); // Hook the VSYNC interrupt dwEnable = READ_GLINT_CTRL_REG(IntEnable); dwEnable |= INTR_ENABLE_VIDSTREAM_A; LOAD_GLINT_REG(IntEnable, dwEnable); LOAD_GLINT_REG(VSAInterruptLine, 0); pThisDisplay->VidPort.bActive = TRUE; pThisDisplay->VidPort.bResetStatus = TRUE; pThisDisplay->VidPort.dwErrorCount = 0; } pInput->ddRVal = DD_OK; return DDHAL_DRIVER_HANDLED; } // DdUpdateVideoPort //----------------------------------------------------------------------------- // // DDGetVideoPortConnectInfo // // Passes back the connect info to a client. Can be an array of // available VideoPort Type // //----------------------------------------------------------------------------- DWORD CALLBACK DDGetVideoPortConnectInfo( LPDDHAL_GETVPORTCONNECTDATA pInput) { P3_THUNKEDDATA* pThisDisplay; GET_THUNKEDDATA(pThisDisplay, pInput->lpDD->lpGbl); DISPDBG((DBGLVL,"** In DDGetVideoPortConnectInfo")); // P2 has 1 input and 1 output port, but DirectDraw // VPE only understands input ports (for now). if (pInput->dwPortId != 0) { DISPDBG((WRNLVL, " Invalid port ID: 0x%x", pInput->dwPortId)); pInput->ddRVal = DDERR_INVALIDPARAMS; return(DDHAL_DRIVER_HANDLED); } // Fill in an array of connect info's. if (pInput->lpConnect == NULL) { DISPDBG((DBGLVL," Request for connect number, Port: 0x%x", pInput->dwPortId)); pInput->dwNumEntries = VIDEOPORT_NUM_CONNECT_INFO; pInput->ddRVal = DD_OK; } else { DWORD dwNum; DDVIDEOPORTCONNECT ConnectInfo; DISPDBG((DBGLVL," Request for connect info, Port: 0x%x", pInput->dwPortId)); ZeroMemory(&ConnectInfo, sizeof(DDVIDEOPORTCONNECT)); ConnectInfo.dwSize = sizeof(DDVIDEOPORTCONNECT); ConnectInfo.dwFlags = DDVPCONNECT_VACT | DDVPCONNECT_DISCARDSVREFDATA | DDVPCONNECT_HALFLINE | DDVPCONNECT_INVERTPOLARITY; // 4 GUIDs, 2 Port widths (8 and 16 bits) for (dwNum = 0; dwNum < VIDEOPORT_NUM_CONNECT_INFO; dwNum++) { switch(dwNum) { case 0: ConnectInfo.guidTypeID = DDVPTYPE_E_HREFH_VREFH; ConnectInfo.dwPortWidth = 8; break; case 1: ConnectInfo.guidTypeID = DDVPTYPE_E_HREFH_VREFH; ConnectInfo.dwPortWidth = 16; break; case 2: ConnectInfo.guidTypeID = DDVPTYPE_E_HREFH_VREFL; ConnectInfo.dwPortWidth = 8; break; case 3: ConnectInfo.guidTypeID = DDVPTYPE_E_HREFH_VREFL; ConnectInfo.dwPortWidth = 16; break; case 4: ConnectInfo.guidTypeID = DDVPTYPE_E_HREFL_VREFH; ConnectInfo.dwPortWidth = 8; break; case 5: ConnectInfo.guidTypeID = DDVPTYPE_E_HREFL_VREFH; ConnectInfo.dwPortWidth = 16; break; case 6: ConnectInfo.guidTypeID = DDVPTYPE_E_HREFL_VREFL; ConnectInfo.dwPortWidth = 8; break; case 7: ConnectInfo.guidTypeID = DDVPTYPE_E_HREFL_VREFL; ConnectInfo.dwPortWidth = 16; break; } memcpy((pInput->lpConnect + dwNum), &ConnectInfo, sizeof(DDVIDEOPORTCONNECT)); } pInput->dwNumEntries = VIDEOPORT_NUM_CONNECT_INFO; pInput->ddRVal = DD_OK; } return DDHAL_DRIVER_HANDLED; } // DDGetVideoPortConnectInfo //----------------------------------------------------------------------------- // // DdCanCreateVideoPort // // Can the VideoPort be created? // //----------------------------------------------------------------------------- DWORD CALLBACK DdCanCreateVideoPort ( LPDDHAL_CANCREATEVPORTDATA pInput) { DWORD dwFlags = 0; LPDDVIDEOPORTDESC lpVPDesc; LPDDVIDEOPORTCONNECT lpVPConn; P3_THUNKEDDATA* pThisDisplay; lpVPDesc = pInput->lpDDVideoPortDesc; lpVPConn = &(pInput->lpDDVideoPortDesc->VideoPortType); GET_THUNKEDDATA(pThisDisplay, pInput->lpDD->lpGbl); DISPDBG((DBGLVL,"** In DdCanCreateVideoPort")); DUMPVPORT(DBGLVL,*pInput->lpDDVideoPortDesc); // Start with DD_OK. If we are asked for parameters that we don't // support, then set the flag to DDERR_INVALIDPARAMS. pInput->ddRVal = DD_OK; // Check the video port ID if (lpVPDesc->dwVideoPortID != 0) { DISPDBG((DBGLVL, " Invalid port ID: %d", lpVPDesc->dwVideoPortID)); pInput->ddRVal = DDERR_INVALIDPARAMS; } // Check the video field width if (lpVPDesc->dwFieldWidth > VIDEOPORT_MAX_FIELD_WIDTH) { pInput->ddRVal = DDERR_INVALIDPARAMS; DISPDBG((DBGLVL, " Invalid video field width: %d", lpVPDesc->dwFieldWidth)); } // Check the VBI field width if (lpVPDesc->dwVBIWidth > VIDEOPORT_MAX_VBI_WIDTH) { pInput->ddRVal = DDERR_INVALIDPARAMS; DISPDBG((DBGLVL, " Invalid VBI field width: %d", lpVPDesc->dwVBIWidth)); } // Check the field height if (lpVPDesc->dwFieldHeight > VIDEOPORT_MAX_FIELD_HEIGHT) { pInput->ddRVal = DDERR_INVALIDPARAMS; DISPDBG((DBGLVL, " Invalid video field height: %d", lpVPDesc->dwFieldHeight)); } // Check the connection GUID if ( MATCH_GUID((lpVPConn->guidTypeID), DDVPTYPE_CCIR656) || MATCH_GUID((lpVPConn->guidTypeID), DDVPTYPE_BROOKTREE) || MATCH_GUID((lpVPConn->guidTypeID), DDVPTYPE_PHILIPS) ) { pInput->ddRVal = DDERR_INVALIDPARAMS; DISPDBG((DBGLVL, " Invalid connection GUID")); } // Check the port width if ( !((lpVPConn->dwPortWidth == 8) || (lpVPConn->dwPortWidth == 16)) ) { pInput->ddRVal = DDERR_INVALIDPARAMS; DISPDBG((DBGLVL, " Invalid port width: %d", lpVPConn->dwPortWidth)); } // All the flags we don't support dwFlags = DDVPCONNECT_DOUBLECLOCK | DDVPCONNECT_SHAREEVEN | DDVPCONNECT_SHAREODD; // Check the flags if (lpVPConn->dwFlags & dwFlags) { pInput->ddRVal = DDERR_INVALIDPARAMS; DISPDBG((DBGLVL, " Invalid flags: 0x%x", lpVPConn->dwFlags)); } return DDHAL_DRIVER_HANDLED; } // DdCanCreateVideoPort //----------------------------------------------------------------------------- // // DdCreateVideoPort // // This function is optional // //----------------------------------------------------------------------------- DWORD CALLBACK DdCreateVideoPort ( LPDDHAL_CREATEVPORTDATA pInput) { VMIREQUEST vmi_inreq; VMIREQUEST vmi_outreq; BOOL bRet; int SurfaceNum = 0; P3_THUNKEDDATA* pThisDisplay; GET_THUNKEDDATA(pThisDisplay, pInput->lpDD->lpGbl); DISPDBG((DBGLVL,"** In DdCreateVideoPort")); // Reset the structure for the videoport info memset(&pThisDisplay->VidPort, 0, sizeof(pThisDisplay->VidPort)); ZeroMemory(&vmi_inreq, sizeof(VMIREQUEST)); ZeroMemory(&vmi_outreq, sizeof(VMIREQUEST)); vmi_inreq.dwSize = sizeof(VMIREQUEST); vmi_inreq.dwDevNode = pThisDisplay->dwDevNode; vmi_inreq.dwOperation = GLINT_VMI_GETMUTEX_A; vmi_inreq.dwMutex = 0; bRet = VXDCommand(GLINT_VMI_COMMAND, &vmi_inreq, sizeof(VMIREQUEST), &vmi_outreq, sizeof(VMIREQUEST)); if (!bRet || (vmi_outreq.dwMutex == 0)) { DISPDBG((WRNLVL,"WARNING: Couldn't get Mutex for stream A - VFW running?")); pInput->ddRVal = DDERR_GENERIC; return DDHAL_DRIVER_HANDLED; } pThisDisplay->VidPort.dwMutexA = vmi_outreq.dwMutex; // Ensure the port is marked as not created and not on pThisDisplay->VidPort.bCreated = FALSE; pThisDisplay->VidPort.bActive = FALSE; WAIT_GLINT_FIFO(2); // Make sure the port is disabled. LOAD_GLINT_REG(VSAControl, __PERMEDIA_DISABLE); // Keep a copy of the videoport description DUMPVPORT(0,*pInput->lpDDVideoPortDesc); // Succesfully created the VideoPort. pThisDisplay->VidPort.bCreated = TRUE; // Depending on the GUID, decide on the Status of the HREF and VREF lines if (MATCH_GUID((pInput->lpDDVideoPortDesc->VideoPortType.guidTypeID), DDVPTYPE_E_HREFH_VREFH)) { DISPDBG((DBGLVL," GUID: DDVPTYPE_E_HREFH_VREFH")); pThisDisplay->VidPort.dwStreamAFlags = VIDEOPORT_HREF_ACTIVE_HIGH | VIDEOPORT_VREF_ACTIVE_HIGH; } else if (MATCH_GUID((pInput->lpDDVideoPortDesc->VideoPortType.guidTypeID), DDVPTYPE_E_HREFH_VREFL)) { DISPDBG((DBGLVL," GUID: DDVPTYPE_E_HREFH_VREFH")); pThisDisplay->VidPort.dwStreamAFlags = VIDEOPORT_HREF_ACTIVE_HIGH; } else if (MATCH_GUID((pInput->lpDDVideoPortDesc->VideoPortType.guidTypeID), DDVPTYPE_E_HREFL_VREFH)) { DISPDBG((DBGLVL," GUID: DDVPTYPE_E_HREFH_VREFH")); pThisDisplay->VidPort.dwStreamAFlags = VIDEOPORT_VREF_ACTIVE_HIGH; } else if (MATCH_GUID((pInput->lpDDVideoPortDesc->VideoPortType.guidTypeID), DDVPTYPE_E_HREFL_VREFL)) { DISPDBG((DBGLVL," GUID: DDVPTYPE_E_HREFH_VREFH")); pThisDisplay->VidPort.dwStreamAFlags = 0; } else { DISPDBG((ERRLVL,"ERROR: Unsupported VideoType GUID!")); pThisDisplay->VidPort.dwStreamAFlags = 0; } pInput->ddRVal = DD_OK; return DDHAL_DRIVER_NOTHANDLED; } // DdCreateVideoPort //----------------------------------------------------------------------------- // // DdFlipVideoPort // // This function is required // //----------------------------------------------------------------------------- DWORD CALLBACK DdFlipVideoPort ( LPDDHAL_FLIPVPORTDATA pInput) { P3_THUNKEDDATA* pThisDisplay; DWORD dwChipIndex; DWORD OutCount = 0; GET_THUNKEDDATA(pThisDisplay, pInput->lpDD->lpGbl); DISPDBG((DBGLVL,"** In DdFlipVideoPort")); if (pThisDisplay->VidPort.bActive) { #if DBG if ( pThisDisplay->pGLInfo->dwPeriodVideoVBL != 0 ) { if ( pThisDisplay->pGLInfo->dwVideoEventHandle == (DWORD)NULL ) { DISPDBG((WRNLVL,"** DdFlipVideoPort: was autoflipping on bogus event handle.")); } if ( !g_bFlipVideoPortDoingAutoflip ) { DISPDBG((DBGLVL,"** DdFlipVideoPort: already autoflipping!")); } } #endif // Don't allow us to catch up with the video do { dwChipIndex = READ_GLINT_CTRL_REG(VSAVideoAddressIndex); } while (dwChipIndex == pThisDisplay->VidPort.dwCurrentHostFrame); pThisDisplay->VidPort.dwCurrentHostFrame++; if (pThisDisplay->VidPort.dwCurrentHostFrame >= pThisDisplay->VidPort.dwNumSurfaces) { pThisDisplay->VidPort.dwCurrentHostFrame = 0; } // Need to sync to ensure that a blit from the source surface has finished.. SYNC_WITH_GLINT; // Advance the count LOAD_GLINT_REG(VSAVideoAddressHost, pThisDisplay->VidPort.dwCurrentHostFrame); } pInput->ddRVal = DD_OK; return DDHAL_DRIVER_HANDLED; } // DdFlipVideoPort //----------------------------------------------------------------------------- // // DdGetVideoPortBandwidth // // This function is required // //----------------------------------------------------------------------------- DWORD CALLBACK DdGetVideoPortBandwidth ( LPDDHAL_GETVPORTBANDWIDTHDATA pInput) { P3_THUNKEDDATA* pThisDisplay; DDVIDEOPORTBANDWIDTH *lpOutput = pInput->lpBandwidth; DDVIDEOPORTINFO *pInfo = &(pInput->lpVideoPort->ddvpInfo); DDVIDEOPORTDESC *pDesc = &(pInput->lpVideoPort->ddvpDesc); GET_THUNKEDDATA(pThisDisplay, pInput->lpDD->lpGbl); DISPDBG((DBGLVL,"** In DdGetVideoPortBandwidth")); lpOutput->dwSize = sizeof(DDVIDEOPORTBANDWIDTH); lpOutput->dwCaps = DDVPBCAPS_DESTINATION; if (!(pInput->dwFlags & DDVPB_TYPE)) { lpOutput->dwOverlay = 20; lpOutput->dwColorkey = 20; lpOutput->dwYInterpolate = 20; lpOutput->dwYInterpAndColorkey = 20; } pInput->ddRVal = DD_OK; return DDHAL_DRIVER_HANDLED; } // DdGetVideoPortBandwidth //----------------------------------------------------------------------------- // // GetVideoPortInputFormat32 // // This function is required // //----------------------------------------------------------------------------- DWORD CALLBACK DdGetVideoPortInputFormats ( LPDDHAL_GETVPORTINPUTFORMATDATA pInput) { P3_THUNKEDDATA* pThisDisplay; DDPIXELFORMAT pf[] = { {sizeof(DDPIXELFORMAT),DDPF_FOURCC, FOURCC_YUV422 ,16,(DWORD)-1,(DWORD)-1,(DWORD)-1}, }; GET_THUNKEDDATA(pThisDisplay, pInput->lpDD->lpGbl); DISPDBG((DBGLVL,"** In DdGetVideoPortInputFormats")); // // The HAL is gaurenteed that the buffer in pInput->lpddpfFormat // is large enough to hold the information // pInput->dwNumFormats = 1; if (pInput->lpddpfFormat != NULL) { memcpy (pInput->lpddpfFormat, pf, sizeof (DDPIXELFORMAT)); } pInput->ddRVal = DD_OK; return DDHAL_DRIVER_HANDLED; } // GetVideoPortInputFormat32 //----------------------------------------------------------------------------- // // DdGetVideoPortOutputFormats // // This function is required // //----------------------------------------------------------------------------- DWORD CALLBACK DdGetVideoPortOutputFormats ( LPDDHAL_GETVPORTOUTPUTFORMATDATA pInput) { P3_THUNKEDDATA* pThisDisplay; DDPIXELFORMAT pf[] = { {sizeof(DDPIXELFORMAT),DDPF_FOURCC, FOURCC_YUV422 ,16,(DWORD)-1,(DWORD)-1,(DWORD)-1}, }; GET_THUNKEDDATA(pThisDisplay, pInput->lpDD->lpGbl); DISPDBG((DBGLVL,"** In DdGetVideoPortOutputFormats")); // This says that if the input format of the videoport is YUV then the output will also be // YUV to the surface if (pInput->lpddpfInputFormat->dwFlags & DDPF_FOURCC ) { if (pInput->lpddpfInputFormat->dwFourCC == FOURCC_YUV422) { pInput->dwNumFormats = 1; if (pInput->lpddpfOutputFormats != NULL) { memcpy (pInput->lpddpfOutputFormats, pf, sizeof (DDPIXELFORMAT)); } } } pInput->ddRVal = DD_OK; return DDHAL_DRIVER_HANDLED; } // DdGetVideoPortOutputFormats //----------------------------------------------------------------------------- // // DdGetVideoPortField // // This function is only required if readback of the current // field is supported. // //----------------------------------------------------------------------------- DWORD CALLBACK DdGetVideoPortField ( LPDDHAL_GETVPORTFIELDDATA pInput) { DWORD i = 0; DWORD dwIndex = 0; DWORD dwMask = 0; DWORD dwStatus = 0; P3_THUNKEDDATA* pThisDisplay; GET_THUNKEDDATA(pThisDisplay, pInput->lpDD->lpGbl); DISPDBG((DBGLVL,"** In DdGetVideoPortField")); // // Make sure the video port is ON. If not, set // pInput->ddRVal to DDERR_VIDEONOTACTIVE and return. // if (pThisDisplay->VidPort.bActive == FALSE) { pInput->ddRVal = DDERR_VIDEONOTACTIVE; } else { DWORD dwCurrentIndex; // Read the current index and compare with us. If the same then // we haven't finished drawing. do { dwCurrentIndex = READ_GLINT_CTRL_REG(VSAVideoAddressIndex); } while (pThisDisplay->VidPort.dwCurrentHostFrame == dwCurrentIndex); pInput->bField = (BOOL)((pThisDisplay->pGLInfo->dwVSAPolarity >> pThisDisplay->VidPort.dwCurrentHostFrame) & 0x1); //pInput->bField = !pInput->bField; DISPDBG((DBGLVL,"Returning Field %d's Polarity " "- %d (dwVSAPolarity = 0x%x)", pThisDisplay->VidPort.dwCurrentHostFrame, pInput->bField, pThisDisplay->pGLInfo->dwVSAPolarity)); pInput->ddRVal = DD_OK; } return DDHAL_DRIVER_HANDLED; } // DdGetVideoPortField //----------------------------------------------------------------------------- // // DdGetVideoPortLine // // This function is only required if readback of the current // video line number (0 relative) is supported. // //----------------------------------------------------------------------------- DWORD CALLBACK DdGetVideoPortLine ( LPDDHAL_GETVPORTLINEDATA pInput) { P3_THUNKEDDATA* pThisDisplay; DWORD dwCurrentLine; GET_THUNKEDDATA(pThisDisplay, pInput->lpDD->lpGbl); DISPDBG((DBGLVL,"** In DdGetVideoPortLine")); if (pThisDisplay->VidPort.bActive == FALSE) { pInput->ddRVal = DDERR_VIDEONOTACTIVE; } else { dwCurrentLine = READ_GLINT_CTRL_REG(VSACurrentLine); pInput->dwLine = dwCurrentLine; pInput->ddRVal = DD_OK; } return DDHAL_DRIVER_HANDLED; } // DdGetVideoPortLine //----------------------------------------------------------------------------- // // DdDestroyVideoPort // // This optional function notifies the HAL when the video port // has been destroyed. // //----------------------------------------------------------------------------- DWORD CALLBACK DdDestroyVideoPort ( LPDDHAL_DESTROYVPORTDATA pInput) { P3_THUNKEDDATA* pThisDisplay; VMIREQUEST vmi_inreq; VMIREQUEST vmi_outreq; BOOL bRet; GET_THUNKEDDATA(pThisDisplay, pInput->lpDD->lpGbl); DISPDBG((DBGLVL,"** In DdDestroyVideoPort")); // Ensure the port is off. WAIT_GLINT_FIFO(2); // Disablet the videoport LOAD_GLINT_REG(VSAControl, __PERMEDIA_DISABLE); // Ensure the port is marked as not created and not on pThisDisplay->VidPort.bCreated = FALSE; pThisDisplay->VidPort.bActive = FALSE; // Release the mutex on Stream A if (pThisDisplay->VidPort.dwMutexA != 0) { DISPDBG((DBGLVL," Releasing StreamA Mutex")); ZeroMemory(&vmi_inreq, sizeof(VMIREQUEST)); ZeroMemory(&vmi_outreq, sizeof(VMIREQUEST)); vmi_inreq.dwSize = sizeof(VMIREQUEST); vmi_inreq.dwDevNode = pThisDisplay->dwDevNode; vmi_inreq.dwOperation = GLINT_VMI_RELEASEMUTEX_A; vmi_inreq.dwMutex = pThisDisplay->VidPort.dwMutexA; bRet = VXDCommand(GLINT_VMI_COMMAND, &vmi_inreq, sizeof(VMIREQUEST), &vmi_outreq, sizeof(VMIREQUEST)); ASSERTDD(bRet,"ERROR: Couldn't release Mutex on Stream A"); } // Reset the structure memset(&pThisDisplay->VidPort, 0, sizeof(pThisDisplay->VidPort)); // Stop any autoflipping. if ( pThisDisplay->pGLInfo->dwPeriodVideoVBL != 0 ) { #if DBG if ( pThisDisplay->pGLInfo->dwVideoEventHandle == (DWORD)NULL ) { DISPDBG((WRNLVL,"** DdDestroyVideoPort: " "was autoflipping on bogus event handle.")); } #endif pThisDisplay->pGLInfo->dwPeriodVideoVBL = 0; pThisDisplay->pGLInfo->dwCountdownVideoVBL = 0; DISPDBG((DBGLVL,"** DdDestroyVideoPort: autoflipping now disabled.")); } // Make sure the videoport is turned off pInput->ddRVal = DD_OK; return DDHAL_DRIVER_NOTHANDLED; } // DdDestroyVideoPort //----------------------------------------------------------------------------- // // DdGetVideoSignalStatus // //----------------------------------------------------------------------------- DWORD CALLBACK DdGetVideoSignalStatus( LPDDHAL_GETVPORTSIGNALDATA pInput) { P3_THUNKEDDATA* pThisDisplay; DWORD dwCurrentIndex; BOOL bOK = FALSE; GET_THUNKEDDATA(pThisDisplay, pInput->lpDD->lpGbl); dwCurrentIndex = READ_GLINT_CTRL_REG(VSAVideoAddressIndex); // If the host count matches the index count then the video may be stuck if (pThisDisplay->VidPort.dwCurrentHostFrame == dwCurrentIndex) { bOK = __VD_CheckVideoPortStatus(pThisDisplay, TRUE); } else { bOK = TRUE; } if (!bOK) { pInput->dwStatus = DDVPSQ_NOSIGNAL; } else { pInput->dwStatus = DDVPSQ_SIGNALOK; } pInput->ddRVal = DD_OK; return DDHAL_DRIVER_HANDLED; } // DdGetVideoSignalStatus //----------------------------------------------------------------------------- // // DdGetVideoPortFlipStatus // // This required function allows DDRAW to restrict access to a surface // until the physical flip has occurred, allowing doubled buffered capture. // //----------------------------------------------------------------------------- DWORD CALLBACK DdGetVideoPortFlipStatus ( LPDDHAL_GETVPORTFLIPSTATUSDATA pInput) { P3_THUNKEDDATA* pThisDisplay; DWORD dwCurrentIndex; GET_THUNKEDDATA(pThisDisplay, pInput->lpDD->lpGbl); DISPDBG((DBGLVL,"** In DdGetVideoPortFlipStatus")); pInput->ddRVal = DD_OK; if (pThisDisplay->VidPort.bActive == TRUE) { // If we are flipping, check the currently rendered frame // Read the current index and compare with us. If the same then // we haven't finished drawing. dwCurrentIndex = READ_GLINT_CTRL_REG(VSAVideoAddressIndex); if (pThisDisplay->VidPort.dwCurrentHostFrame == dwCurrentIndex) { // If the videoport is not stuck return that we are still drawing if (__VD_CheckVideoPortStatus(pThisDisplay, FALSE)) { pInput->ddRVal = DDERR_WASSTILLDRAWING; } else { pInput->ddRVal = DD_OK; } } } return DDHAL_DRIVER_HANDLED; } // DdGetVideoPortFlipStatus //----------------------------------------------------------------------------- // // DdWaitForVideoPortSync // // This function is required // //----------------------------------------------------------------------------- DWORD CALLBACK DdWaitForVideoPortSync ( LPDDHAL_WAITFORVPORTSYNCDATA pInput) { P3_THUNKEDDATA* pThisDisplay; GET_THUNKEDDATA(pThisDisplay, pInput->lpDD->lpGbl); DISPDBG((DBGLVL,"** In DdWaitForVideoPortSync")); //@@BEGIN_DDKSPLIT /* * Make sure the video port is ON. If not, set * pInput->ddRVal to DDERR_VIDEONOTACTIVE and return. */ /* if (pInput->dwFlags == DDVPEVENT_BEGIN) { pInput->ddRVal = DD_OK; } else if (pInput->dwFlags == DDVPEVENT_END) { pInput->ddRVal = DD_OK; } */ //@@END_DDKSPLIT pInput->ddRVal = DD_OK; return DDHAL_DRIVER_HANDLED; } // DdWaitForVideoPortSync //----------------------------------------------------------------------------- // // DdSyncSurfaceData // //----------------------------------------------------------------------------- DWORD CALLBACK DdSyncSurfaceData( LPDDHAL_SYNCSURFACEDATA pInput) { P3_THUNKEDDATA* pThisDisplay; GET_THUNKEDDATA(pThisDisplay, pInput->lpDD->lpGbl); DISPDBG((DBGLVL,"** In DdSyncSurfaceData")); DBGDUMP_DDRAWSURFACE_LCL(3, pInput->lpDDSurface); if (!(pInput->lpDDSurface->ddsCaps.dwCaps & DDSCAPS_OVERLAY)) { DISPDBG((DBGLVL, "Surface is not an overlay - not handling")); pInput->ddRVal = DD_OK; return DDHAL_DRIVER_NOTHANDLED; } if (pInput->lpDDSurface->lpGbl->dwGlobalFlags & DDRAWISURFGBL_SOFTWAREAUTOFLIP) { DISPDBG((DBGLVL, "Autoflipping in software")); } pInput->dwSurfaceOffset = pInput->lpDDSurface->lpGbl->fpVidMem - pThisDisplay->dwScreenFlatAddr; pInput->dwOverlayOffset = pInput->dwSurfaceOffset; pInput->ddRVal = DD_OK; return DDHAL_DRIVER_HANDLED; } // DdSyncSurfaceData //----------------------------------------------------------------------------- // // DdSyncVideoPortData // //----------------------------------------------------------------------------- DWORD CALLBACK DdSyncVideoPortData( LPDDHAL_SYNCVIDEOPORTDATA pInput) { P3_THUNKEDDATA* pThisDisplay; GET_THUNKEDDATA(pThisDisplay, pInput->lpDD->lpGbl); DISPDBG((DBGLVL,"** In DdSyncVideoPortData")); pInput->ddRVal = DD_OK; return DDHAL_DRIVER_HANDLED; } // DdSyncVideoPortData //----------------------------------------------------------------------------- // // UpdateOverlay32 // //----------------------------------------------------------------------------- DWORD CALLBACK UpdateOverlay32( LPDDHAL_UPDATEOVERLAYDATA puod) { P3_THUNKEDDATA* pThisDisplay; LPDDRAWI_DDRAWSURFACE_LCL lpSrcSurf; HDC hDC; DWORD dwDstColourKey; DWORD dwSrcColourKey; GET_THUNKEDDATA(pThisDisplay, puod->lpDD); /* * A puod looks like this: * * LPDDRAWI_DIRECTDRAW_GBL lpDD; // driver struct * LPDDRAWI_DDRAWSURFACE_LCL lpDDDestSurface; // dest surface * RECTL rDest; // dest rect * LPDDRAWI_DDRAWSURFACE_LCL lpDDSrcSurface; // src surface * RECTL rSrc; // src rect * DWORD dwFlags; // flags * DDOVERLAYFX overlayFX; // overlay FX * HRESULT ddRVal; // return value * LPDDHALSURFCB_UPDATEOVERLAY UpdateOverlay; // PRIVATE: ptr to callback */ DISPDBG ((DBGLVL,"**In UpdateOverlay32")); lpSrcSurf = puod->lpDDSrcSurface; /* * In the LPDDRAWI_DDRAWSURFACE_LCL, we have the following cool data, * making life much easier: * * HOWEVER! It appears that UpdateOverlay32 is called before any of these * values are changed, so use the values passed in instead. * * DDCOLORKEY ddckCKSrcOverlay; // color key for source overlay use * DDCOLORKEY ddckCKDestOverlay; // color key for destination overlay use * LPDDRAWI_DDRAWSURFACE_INT lpSurfaceOverlaying; // surface we are overlaying * DBLNODE dbnOverlayNode; * * // * //overlay rectangle, used by DDHEL * // * RECT rcOverlaySrc; * RECT rcOverlayDest; * // * //the below values are kept here for ddhel. they're set by UpdateOverlay, * //they're used whenever the overlays are redrawn. * // * DWORD dwClrXparent; // the *actual* color key (override, colorkey, or CLR_INVALID) * DWORD dwAlpha; // the per surface alpha * // * //overlay position * // * LONG lOverlayX; // current x position * LONG lOverlayY; // current y position */ #if DBG // Standard integrity test. if ( pThisDisplay->bOverlayVisible == 0 ) { if ( (LPDDRAWI_DDRAWSURFACE_LCL)pThisDisplay->OverlaySrcSurfLcl != NULL ) { // If overlay is not visible, the current surface should be NULL. DISPDBG((DBGLVL,"** UpdateOverlay32 - vis==0,srcsurf!=NULL")); } } else { if ( (LPDDRAWI_DDRAWSURFACE_LCL)pThisDisplay->OverlaySrcSurfLcl == NULL ) { // If overlay is visible, the current surface should not be NULL. DISPDBG((DBGLVL,"** UpdateOverlay32 - vis!=0,srcsurf==NULL")); } } #endif //DBG if ( ( puod->dwFlags & DDOVER_HIDE ) != 0 ) { DISPDBG((DBGLVL,"** UpdateOverlay32 - hiding.")); // Hide the overlay. if ( pThisDisplay->bOverlayVisible == 0 ) { // No overlay being shown. DISPDBG((WRNLVL,"** UpdateOverlay32 - DDOVER_HIDE - already hidden.")); puod->ddRVal = DDERR_OUTOFCAPS; return DDHAL_DRIVER_HANDLED; } if ( pThisDisplay->OverlaySrcSurfLcl != (ULONG_PTR)lpSrcSurf ) { // This overlay isn't being shown. DISPDBG((WRNLVL,"** UpdateOverlay32 - DDOVER_HIDE - not current overlay surface.")); puod->ddRVal = DDERR_OUTOFCAPS; return DDHAL_DRIVER_HANDLED; } // Stop any autoflipping. if ( pThisDisplay->pGLInfo->dwPeriodVideoVBL != 0 ) { #if DBG if ( pThisDisplay->pGLInfo->dwVideoEventHandle == (DWORD)NULL ) { DISPDBG((WRNLVL,"** UpdateOverlay32 - DDOVER_HIDE - was autoflipping on bogus event handle.")); } #endif pThisDisplay->pGLInfo->dwPeriodVideoVBL = 0; pThisDisplay->pGLInfo->dwCountdownVideoVBL = 0; DISPDBG((DBGLVL,"** UpdateOverlay32 - DDOVER_HIDE - autoflipping now disabled.")); } if ( pThisDisplay->pGLInfo->dwPeriodMonitorVBL != 0 ) { if ( pThisDisplay->pGLInfo->dwMonitorEventHandle == (DWORD)NULL ) { DISPDBG((DBGLVL,"** UpdateOverlay32 - DDOVER_HIDE - was autoupdating on bogus event handle.")); } pThisDisplay->pGLInfo->dwPeriodMonitorVBL = 0; pThisDisplay->pGLInfo->dwCountdownMonitorVBL = 0; DISPDBG((DBGLVL,"** UpdateOverlay32 - DDOVER_HIDE - autoupdate now disabled.")); } // DISPDBG((DBGLVL,"** UpdateOverlay32 (hiding) destroying rect memory.")); // Free the rect memory if ( (void *)pThisDisplay->OverlayClipRgnMem != NULL ) { HEAP_FREE ((void *)pThisDisplay->OverlayClipRgnMem); } pThisDisplay->OverlayClipRgnMem = (ULONG_PTR)NULL; pThisDisplay->OverlayClipRgnMemSize = (DWORD)0; // DISPDBG((DBGLVL,"** UpdateOverlay32 (hiding) destroyed rect memory.")); pThisDisplay->bOverlayVisible = FALSE; pThisDisplay->OverlayDstRectL = (DWORD)0; pThisDisplay->OverlayDstRectR = (DWORD)0; pThisDisplay->OverlayDstRectT = (DWORD)0; pThisDisplay->OverlayDstRectB = (DWORD)0; pThisDisplay->OverlaySrcRectL = (DWORD)0; pThisDisplay->OverlaySrcRectR = (DWORD)0; pThisDisplay->OverlaySrcRectT = (DWORD)0; pThisDisplay->OverlaySrcRectB = (DWORD)0; pThisDisplay->OverlayDstSurfLcl = (ULONG_PTR)NULL; pThisDisplay->OverlaySrcSurfLcl = (ULONG_PTR)NULL; pThisDisplay->OverlayDstColourKey = (DWORD)CLR_INVALID; pThisDisplay->OverlaySrcColourKey = (DWORD)CLR_INVALID; pThisDisplay->OverlayUpdateCountdown = 0; pThisDisplay->bOverlayFlippedThisVbl = (DWORD)FALSE; pThisDisplay->bOverlayUpdatedThisVbl = (DWORD)FALSE; pThisDisplay->pGLInfo->bOverlayEnabled = (DWORD)FALSE; pThisDisplay->pGLInfo->dwOverlayRectL = (DWORD)0; pThisDisplay->pGLInfo->dwOverlayRectR = (DWORD)0; pThisDisplay->pGLInfo->dwOverlayRectT = (DWORD)0; pThisDisplay->pGLInfo->dwOverlayRectB = (DWORD)0; pThisDisplay->pGLInfo->bOverlayColourKeyEnabled = (DWORD)FALSE; pThisDisplay->pGLInfo->dwOverlayDstColourKeyChip = (DWORD)-1; pThisDisplay->pGLInfo->dwOverlayDstColourKeyFB = (DWORD)-1; pThisDisplay->pGLInfo->dwOverlayAlphaSetFB = (DWORD)-1; // Clean up the temporary buffer, if any. if ( pThisDisplay->OverlayTempSurf.VidMem != (ULONG_PTR)NULL ) { FreeStretchBuffer ( pThisDisplay, pThisDisplay->OverlayTempSurf.VidMem ); pThisDisplay->OverlayTempSurf.VidMem = (ULONG_PTR)NULL; pThisDisplay->OverlayTempSurf.Pitch = (DWORD)0; } // Restart the 2D renderer with non-overlay functions. hDC = CREATE_DRIVER_DC ( pThisDisplay->pGLInfo ); if ( hDC != NULL ) { ExtEscape ( hDC, GLINT_OVERLAY_ESCAPE, 0, NULL, 0, NULL ); DELETE_DRIVER_DC ( hDC ); } else { DISPDBG((ERRLVL,"** UpdateOverlay32 - CREATE_DRIVER_DC failed")); } puod->ddRVal = DD_OK; return DDHAL_DRIVER_HANDLED; } else if ( ( ( puod->dwFlags & DDOVER_SHOW ) != 0 ) || ( pThisDisplay->bOverlayVisible != 0 ) ) { { // Catch the dodgy call made by the Demon helper. // This is very bad, but it's the only way I can see to // get Demon to call these two functions. // Remember that the various surfaces and so on are just // to get DD to relax and accept life. // The first three numbers are just that - magic numbers, // and the last one shows which of a range of calls need to be made, // as well as being a magic number itself. if ( ( ( puod->dwFlags & DDOVER_SHOW ) != 0 ) && ( ( puod->dwFlags & DDOVER_KEYDESTOVERRIDE ) != 0 ) && ( ( puod->dwFlags & DDOVER_DDFX ) != 0 ) ) { // OK, looks like a valid call from Demon. if ( ( puod->overlayFX.dckDestColorkey.dwColorSpaceLowValue == GLDD_MAGIC_AUTOFLIPOVERLAY_DL ) && ( puod->overlayFX.dckDestColorkey.dwColorSpaceHighValue == GLDD_MAGIC_AUTOFLIPOVERLAY_DH ) ) { puod->ddRVal = __VD_AutoflipOverlay(); // the return value is actually a benign DD error // value, but GLDD_AUTO_RET_* are also aliased to the // right one for useabiliy. return DDHAL_DRIVER_HANDLED; } else if ( ( puod->overlayFX.dckDestColorkey.dwColorSpaceLowValue == GLDD_MAGIC_AUTOUPDATEOVERLAY_DL ) && ( puod->overlayFX.dckDestColorkey.dwColorSpaceHighValue == GLDD_MAGIC_AUTOUPDATEOVERLAY_DH ) ) { puod->ddRVal = __VD_AutoupdateOverlay(); // the return value is actually a benign DD error // value, but GLDD_AUTO_RET_* are also aliased to the // right one for useabiliy. return DDHAL_DRIVER_HANDLED; } } } DISPDBG((DBGLVL,"** UpdateOverlay32 - showing or reshowing.")); // Either we need to show this, or it is already being shown. if ( ( pThisDisplay->bOverlayVisible != 0 ) && ( pThisDisplay->OverlaySrcSurfLcl != (ULONG_PTR)lpSrcSurf ) ) { // Overlay being shown and source surfaces don't match. // i.e. someone else wants an overlay, but it's already in use. DISPDBG((DBGLVL,"** UpdateOverlay32 - overlay already being shown, returning DDERR_OUTOFCAPS")); puod->ddRVal = DDERR_OUTOFCAPS; return DDHAL_DRIVER_HANDLED; } // Clean up the temporary buffer, if any. if ( pThisDisplay->OverlayTempSurf.VidMem != (ULONG_PTR)NULL ) { FreeStretchBuffer ( pThisDisplay, pThisDisplay->OverlayTempSurf.VidMem ); pThisDisplay->OverlayTempSurf.VidMem = (ULONG_PTR)NULL; pThisDisplay->OverlayTempSurf.Pitch = (DWORD)0; } // Store all the data in the display's data block. pThisDisplay->bOverlayVisible = TRUE; pThisDisplay->OverlayDstRectL = (DWORD)puod->rDest.left; pThisDisplay->OverlayDstRectR = (DWORD)puod->rDest.right; pThisDisplay->OverlayDstRectT = (DWORD)puod->rDest.top; pThisDisplay->OverlayDstRectB = (DWORD)puod->rDest.bottom; pThisDisplay->OverlaySrcRectL = (DWORD)puod->rSrc.left; pThisDisplay->OverlaySrcRectR = (DWORD)puod->rSrc.right; pThisDisplay->OverlaySrcRectT = (DWORD)puod->rSrc.top; pThisDisplay->OverlaySrcRectB = (DWORD)puod->rSrc.bottom; pThisDisplay->OverlayDstSurfLcl = (ULONG_PTR)puod->lpDDDestSurface; pThisDisplay->OverlaySrcSurfLcl = (ULONG_PTR)lpSrcSurf; pThisDisplay->OverlayUpdateCountdown = 0; pThisDisplay->bOverlayFlippedThisVbl = (DWORD)FALSE; pThisDisplay->bOverlayUpdatedThisVbl = (DWORD)FALSE; pThisDisplay->OverlayDstColourKey = (DWORD)CLR_INVALID; pThisDisplay->OverlaySrcColourKey = (DWORD)CLR_INVALID; pThisDisplay->pGLInfo->bOverlayEnabled = (DWORD)TRUE; // Make sure someone hasn't changed video mode behind our backs. // If an overlay is started in a 16-bit mode and then you change to // an 8-bit mode, the caps bits are rarely checked again, // and certainly not by DirectShow. if ( ( pThisDisplay->bPixShift != GLINTDEPTH16 ) && ( pThisDisplay->bPixShift != GLINTDEPTH32 ) ) { DISPDBG((WRNLVL,"** UpdateOverlay32 - overlay asked for in non-16 or non-32 bit mode. Returning DDERR_OUTOFCAPS")); goto update_overlay_outofcaps_cleanup; } #if 1 // See if there is a clipper or not. If not, this is trying to fly over the // desktop instead of being bound in a window, so object nicely. if ( ( ((LPDDRAWI_DDRAWSURFACE_LCL)pThisDisplay->OverlayDstSurfLcl) != NULL ) && ( ((LPDDRAWI_DDRAWSURFACE_LCL)pThisDisplay->OverlayDstSurfLcl)->lpSurfMore != NULL ) && ( ((LPDDRAWI_DDRAWSURFACE_LCL)pThisDisplay->OverlayDstSurfLcl)->lpSurfMore->lpDDIClipper != NULL ) ) { // Yep, there's a clipper } else { // No clipper. Someone's doing a WHQL test! :-) DISPDBG((WRNLVL,"** UpdateOverlay32 - no clipper on dest surface, returning DDERR_OUTOFCAPS")); goto update_overlay_outofcaps_cleanup; } #endif #if 1 { // Get the cliprect list, and see if it is larger than the // target rectangle. That is a pretty good indication of // Overfly (and indeed anything else that tries anything similar) LPRGNDATA lpRgn; int NumRects; LPRECT lpCurRect; lpRgn = GetOverlayVisibleRects ( pThisDisplay ); if ( lpRgn != NULL ) { // Got a clip region. NumRects = lpRgn->rdh.nCount; if ( NumRects > 0 ) { lpCurRect = (LPRECT)lpRgn->Buffer; while ( NumRects > 0 ) { // The +-5 is a fudge factor to cope with Xing's slight insanities. if ( ( lpCurRect->left < puod->rDest.left - 5 ) || ( lpCurRect->right > puod->rDest.right + 5 ) || ( lpCurRect->top < puod->rDest.top - 5 ) || ( lpCurRect->bottom > puod->rDest.bottom + 5 ) ) { DISPDBG((WRNLVL,"** UpdateOverlay32 - out of range cliprect(s). Returning DDERR_OUTOFCAPS")); goto update_overlay_outofcaps_cleanup; } // Next rect NumRects--; lpCurRect++; } } } } #endif dwDstColourKey = CLR_INVALID; if ( puod->dwFlags & DDOVER_KEYDEST ) { // Use destination surface's destination colourkey for dst key. dwDstColourKey = puod->lpDDDestSurface->ddckCKDestOverlay.dwColorSpaceLowValue; } if ( puod->dwFlags & DDOVER_KEYDESTOVERRIDE ) { // Use DDOVERLAYFX dest colour for dst key. dwDstColourKey = puod->overlayFX.dckDestColorkey.dwColorSpaceLowValue; } dwSrcColourKey = CLR_INVALID; if ( puod->dwFlags & DDOVER_KEYSRC ) { // Use source surface's source colourkey for src key. dwSrcColourKey = puod->lpDDSrcSurface->ddckCKSrcOverlay.dwColorSpaceLowValue; DISPDBG((WRNLVL,"UpdateOverlay32:ERROR! Cannot do source colour key on overlays.")); } if ( puod->dwFlags & DDOVER_KEYSRCOVERRIDE ) { // Use DDOVERLAYFX src colour for src key. dwSrcColourKey = puod->overlayFX.dckSrcColorkey.dwColorSpaceLowValue; DISPDBG((WRNLVL,"UpdateOverlay32:ERROR! Cannot do source colour key overrides on overlays.")); } if ( dwDstColourKey != CLR_INVALID ) { DWORD dwChipColourKey; DWORD dwFBColourKey; DWORD dwFBAlphaSet; // Find the chip's colour key for this display mode. dwChipColourKey = (DWORD)-1; switch ( pThisDisplay->bPixShift ) { case GLINTDEPTH16: if ( pThisDisplay->ddpfDisplay.dwRBitMask == 0x7C00 ) { // 5551 format, as it should be. dwFBColourKey = ( puod->lpDDDestSurface->ddckCKDestOverlay.dwColorSpaceLowValue ) & 0xffff; dwChipColourKey = CHROMA_LOWER_ALPHA(FORMAT_5551_32BIT_BGR(dwFBColourKey)); // Replicate in both words. dwFBColourKey |= dwFBColourKey << 16; dwFBAlphaSet = 0x80008000; } else { // 565 format. Oops. DISPDBG((WRNLVL, "** UpdateOverlay32 error: called for a colourkeyed 565 surface.")); } break; case GLINTDEPTH32: dwFBColourKey = puod->lpDDDestSurface->ddckCKDestOverlay.dwColorSpaceLowValue; dwChipColourKey = CHROMA_LOWER_ALPHA(FORMAT_8888_32BIT_BGR(dwFBColourKey)); dwFBAlphaSet = 0xff000000; break; case GLINTDEPTH8: case GLINTDEPTH24: default: DISPDBG((WRNLVL, "** UpdateOverlay32 error: called for an 8, 24 or unknown surface bPixShift=%d", pThisDisplay->bPixShift)); DISPDBG((ERRLVL,"** UpdateOverlay32 error: see above.")); goto update_overlay_outofcaps_cleanup; break; } if ( dwChipColourKey == (DWORD)-1 ) { DISPDBG((WRNLVL,"UpdateOverlay32:ERROR:Cannot do overlay dest colour keying...")); DISPDBG((WRNLVL,"...in anything but 5551 or 8888 mode - returning DDERR_OUTOFCAPS")); goto update_overlay_outofcaps_cleanup; } pThisDisplay->pGLInfo->bOverlayEnabled = (DWORD)TRUE; pThisDisplay->pGLInfo->dwOverlayDstColourKeyFB = dwFBColourKey; pThisDisplay->pGLInfo->dwOverlayDstColourKeyChip = dwChipColourKey; pThisDisplay->pGLInfo->bOverlayColourKeyEnabled = (DWORD)TRUE; pThisDisplay->pGLInfo->dwOverlayAlphaSetFB = dwFBAlphaSet; // Try to allocate the temporary buffer needed for colourkey stuff. pThisDisplay->OverlayTempSurf.VidMem = AllocStretchBuffer (pThisDisplay, (pThisDisplay->OverlayDstRectR - pThisDisplay->OverlayDstRectL), // width (pThisDisplay->OverlayDstRectB - pThisDisplay->OverlayDstRectT), // height DDSurf_GetChipPixelSize((LPDDRAWI_DDRAWSURFACE_LCL)(pThisDisplay->OverlayDstSurfLcl)), // PixelSize (ULONG_PTR)((LPDDRAWI_DDRAWSURFACE_LCL)(pThisDisplay->OverlayDstSurfLcl))->ddsCaps.dwCaps, (int*)&(pThisDisplay->OverlayTempSurf.Pitch)); if ( pThisDisplay->OverlayTempSurf.VidMem == (ULONG_PTR)NULL ) { // Not enough space - have to fail the overlay DISPDBG((WRNLVL,"UpdateOverlay32:ERROR: not enough memory for buffer - returning DDERR_OUTOFCAPS")); pThisDisplay->OverlayTempSurf.Pitch = (DWORD)0; goto update_overlay_outofcaps_cleanup; } // Restart the 2D renderer with overlay functions. hDC = CREATE_DRIVER_DC ( pThisDisplay->pGLInfo ); if ( hDC != NULL ) { ExtEscape ( hDC, GLINT_OVERLAY_ESCAPE, 0, NULL, 0, NULL ); DELETE_DRIVER_DC ( hDC ); } else { DISPDBG((ERRLVL,"** UpdateOverlay32 - CREATE_DRIVER_DC failed")); } // update the alpha channel UpdateAlphaOverlay ( pThisDisplay ); pThisDisplay->OverlayUpdateCountdown = OVERLAY_UPDATE_WAIT; } else { // No colour key, just an overlay. pThisDisplay->pGLInfo->bOverlayEnabled = (DWORD)TRUE; pThisDisplay->pGLInfo->bOverlayColourKeyEnabled = (DWORD)FALSE; pThisDisplay->pGLInfo->dwOverlayDstColourKeyChip = (DWORD)-1; pThisDisplay->pGLInfo->dwOverlayDstColourKeyFB = (DWORD)-1; pThisDisplay->pGLInfo->dwOverlayAlphaSetFB = (DWORD)-1; // Restart the 2D renderer with non-overlay functions. hDC = CREATE_DRIVER_DC ( pThisDisplay->pGLInfo ); if ( hDC != NULL ) { ExtEscape ( hDC, GLINT_OVERLAY_ESCAPE, 0, NULL, 0, NULL ); DELETE_DRIVER_DC ( hDC ); } else { DISPDBG((ERRLVL,"** UpdateOverlay32 - CREATE_DRIVER_DC failed")); } } // Safely got any memory required, so we can set these up now. pThisDisplay->OverlayDstColourKey = dwDstColourKey; pThisDisplay->OverlaySrcColourKey = dwSrcColourKey; pThisDisplay->pGLInfo->dwOverlayRectL = pThisDisplay->OverlayDstRectL; pThisDisplay->pGLInfo->dwOverlayRectR = pThisDisplay->OverlayDstRectR; pThisDisplay->pGLInfo->dwOverlayRectT = pThisDisplay->OverlayDstRectT; pThisDisplay->pGLInfo->dwOverlayRectB = pThisDisplay->OverlayDstRectB; // Do the update itself. P3TestDrawOverlay ( pThisDisplay, lpSrcSurf, FALSE ); pThisDisplay->bOverlayUpdatedThisVbl = (DWORD)TRUE; if ( ( puod->dwFlags & DDOVER_AUTOFLIP ) == 0 ) { // Start or continue any autoupdates - this is not autoflipping. #if DBG if ( pThisDisplay->pGLInfo->dwMonitorEventHandle == (DWORD)NULL ) { DISPDBG((WRNLVL,"** UpdateOverlay32 - trying to autoupdate using bogus event handle.")); } #endif if ( pThisDisplay->pGLInfo->dwPeriodMonitorVBL == 0 ) { pThisDisplay->pGLInfo->dwPeriodMonitorVBL = OVERLAY_AUTOUPDATE_CYCLE_PERIOD; pThisDisplay->pGLInfo->dwCountdownMonitorVBL = OVERLAY_AUTOUPDATE_RESET_PERIOD; DISPDBG((DBGLVL,"** UpdateOverlay32 - autoupdate now enabled.")); } } else { // This autoflips - stop any autoupdates. if ( pThisDisplay->pGLInfo->dwPeriodMonitorVBL != 0 ) { pThisDisplay->pGLInfo->dwPeriodMonitorVBL = 0; pThisDisplay->pGLInfo->dwCountdownMonitorVBL = 0; DISPDBG((DBGLVL,"** UpdateOverlay32 - autoupdate now disabled because of autoflipping.")); } } // And tell the world about it DISPDBG((DBGLVL,"** In UpdateOverlay32")); DISPDBG((DBGLVL,"** ...Src rect %d,%d -> %d,%d", pThisDisplay->OverlaySrcRectL, pThisDisplay->OverlaySrcRectT, pThisDisplay->OverlaySrcRectR, pThisDisplay->OverlaySrcRectB )); DISPDBG((DBGLVL,"** ...Dst rect %d,%d -> %d,%d", pThisDisplay->OverlayDstRectL, pThisDisplay->OverlayDstRectT, pThisDisplay->OverlayDstRectR, pThisDisplay->OverlayDstRectB )); DISPDBG((DBGLVL,"** ...Src colour key 0x%08x, dst colour key 0x%08x", pThisDisplay->OverlaySrcColourKey, pThisDisplay->OverlayDstColourKey )); } puod->ddRVal = DD_OK; return DDHAL_DRIVER_HANDLED; update_overlay_outofcaps_cleanup: // This cleans up after any partial setup, and returns DDERR_OUTOFCAPS. // It's a clean and easy way of failing at any stage. DISPDBG((DBGLVL,"** UpdateOverlay32 - cleaning up and returning DDERR_OUTOFCAPS.")); // Stop any autoflipping. if ( pThisDisplay->pGLInfo->dwPeriodVideoVBL != 0 ) { #if DBG if ( pThisDisplay->pGLInfo->dwVideoEventHandle == (DWORD)NULL ) { DISPDBG((DBGLVL,"** UpdateOverlay32 - DDOVER_HIDE - was autoflipping on bogus event handle.")); } #endif pThisDisplay->pGLInfo->dwPeriodVideoVBL = 0; pThisDisplay->pGLInfo->dwCountdownVideoVBL = 0; DISPDBG((DBGLVL,"** UpdateOverlay32 - DDOVER_HIDE - autoflipping now disabled.")); } if ( pThisDisplay->pGLInfo->dwPeriodMonitorVBL != 0 ) { #if DBG if ( pThisDisplay->pGLInfo->dwMonitorEventHandle == (DWORD)NULL ) { DISPDBG((DBGLVL,"** UpdateOverlay32 - DDOVER_HIDE - was autoupdating on bogus event handle.")); } #endif pThisDisplay->pGLInfo->dwPeriodMonitorVBL = 0; pThisDisplay->pGLInfo->dwCountdownMonitorVBL = 0; DISPDBG((DBGLVL,"** UpdateOverlay32 - DDOVER_HIDE - autoupdate now disabled.")); } // Free the rect memory if ( (void *)pThisDisplay->OverlayClipRgnMem != NULL ) { HEAP_FREE ((void *)pThisDisplay->OverlayClipRgnMem); } pThisDisplay->OverlayClipRgnMem = (ULONG_PTR)NULL; pThisDisplay->OverlayClipRgnMemSize = (DWORD)0; pThisDisplay->bOverlayVisible = FALSE; pThisDisplay->OverlayDstRectL = (DWORD)0; pThisDisplay->OverlayDstRectR = (DWORD)0; pThisDisplay->OverlayDstRectT = (DWORD)0; pThisDisplay->OverlayDstRectB = (DWORD)0; pThisDisplay->OverlaySrcRectL = (DWORD)0; pThisDisplay->OverlaySrcRectR = (DWORD)0; pThisDisplay->OverlaySrcRectT = (DWORD)0; pThisDisplay->OverlaySrcRectB = (DWORD)0; pThisDisplay->OverlayDstSurfLcl = (ULONG_PTR)NULL; pThisDisplay->OverlaySrcSurfLcl = (ULONG_PTR)NULL; pThisDisplay->OverlayDstColourKey = (DWORD)CLR_INVALID; pThisDisplay->OverlaySrcColourKey = (DWORD)CLR_INVALID; pThisDisplay->OverlayUpdateCountdown = 0; pThisDisplay->bOverlayFlippedThisVbl = (DWORD)FALSE; pThisDisplay->bOverlayUpdatedThisVbl = (DWORD)FALSE; pThisDisplay->pGLInfo->bOverlayEnabled = (DWORD)FALSE; pThisDisplay->pGLInfo->dwOverlayRectL = (DWORD)0; pThisDisplay->pGLInfo->dwOverlayRectR = (DWORD)0; pThisDisplay->pGLInfo->dwOverlayRectT = (DWORD)0; pThisDisplay->pGLInfo->dwOverlayRectB = (DWORD)0; pThisDisplay->pGLInfo->bOverlayColourKeyEnabled = (DWORD)FALSE; pThisDisplay->pGLInfo->dwOverlayDstColourKeyChip = (DWORD)-1; pThisDisplay->pGLInfo->dwOverlayDstColourKeyFB = (DWORD)-1; pThisDisplay->pGLInfo->dwOverlayAlphaSetFB = (DWORD)-1; // Clean up the temporary buffer, if any. if ( pThisDisplay->OverlayTempSurf.VidMem != (ULONG_PTR)NULL ) { FreeStretchBuffer ( pThisDisplay, pThisDisplay->OverlayTempSurf.VidMem ); pThisDisplay->OverlayTempSurf.VidMem = (ULONG_PTR)NULL; pThisDisplay->OverlayTempSurf.Pitch = (DWORD)0; } // Restart the 2D renderer with non-overlay functions. hDC = CREATE_DRIVER_DC ( pThisDisplay->pGLInfo ); if ( hDC != NULL ) { ExtEscape ( hDC, GLINT_OVERLAY_ESCAPE, 0, NULL, 0, NULL ); DELETE_DRIVER_DC ( hDC ); } else { DISPDBG((ERRLVL,"** UpdateOverlay32 - CREATE_DRIVER_DC failed")); } puod->ddRVal = DDERR_OUTOFCAPS; return DDHAL_DRIVER_HANDLED; } DWORD CALLBACK SetOverlayPosition32(LPDDHAL_SETOVERLAYPOSITIONDATA psopd) { P3_THUNKEDDATA* pThisDisplay; GET_THUNKEDDATA(pThisDisplay, psopd->lpDD); // /* // * A psopd looks like this: // * // * LPDDRAWI_DIRECTDRAW_GBL lpDD; // driver struct // * LPDDRAWI_DDRAWSURFACE_LCL lpDDSrcSurface; // src surface // * LPDDRAWI_DDRAWSURFACE_LCL lpDDDestSurface; // dest surface // * LONG lXPos; // x position // * LONG lYPos; // y position // * HRESULT ddRVal; // return value // * LPDDHALSURFCB_SETOVERLAYPOSITION SetOverlayPosition; // PRIVATE: ptr to callback // */ #if DBG // Standard integrity test. if ( pThisDisplay->bOverlayVisible == 0 ) { if ( (LPDDRAWI_DDRAWSURFACE_LCL)pThisDisplay->OverlaySrcSurfLcl != NULL ) { // If overlay is not visible, the current surface should be NULL. DISPDBG((DBGLVL,"** SetOverlayPosition32 - vis==0,srcsurf!=NULL")); } } else { if ( (LPDDRAWI_DDRAWSURFACE_LCL)pThisDisplay->OverlaySrcSurfLcl == NULL ) { // If overlay is visible, the current surface should not be NULL. DISPDBG((DBGLVL,"** SetOverlayPosition32 - vis!=0,srcsurf==NULL")); } } #endif //DBG if ( pThisDisplay->bOverlayVisible == 0 ) { // No overlay is visible. psopd->ddRVal = DDERR_OVERLAYNOTVISIBLE; return DDHAL_DRIVER_HANDLED; } if ( pThisDisplay->OverlaySrcSurfLcl != (ULONG_PTR)psopd->lpDDSrcSurface ) { // This overlay isn't visible. psopd->ddRVal = DDERR_OVERLAYNOTVISIBLE; return DDHAL_DRIVER_HANDLED; } #if DBG if ( pThisDisplay->OverlayDstSurfLcl != (ULONG_PTR)psopd->lpDDDestSurface ) { // Oh dear. The destination surfaces don't agree. DISPDBG((DBGLVL,"** SetOverlayPosition32 - dest surfaces don't agree")); } #endif //DBG // Move the rect pThisDisplay->OverlayDstRectR += (DWORD)( psopd->lXPos - (LONG)pThisDisplay->OverlayDstRectL ); pThisDisplay->OverlayDstRectB += (DWORD)( psopd->lYPos - (LONG)pThisDisplay->OverlayDstRectT ); pThisDisplay->OverlayDstRectL = (DWORD)psopd->lXPos; pThisDisplay->OverlayDstRectT = (DWORD)psopd->lYPos; pThisDisplay->pGLInfo->dwOverlayRectL = pThisDisplay->OverlayDstRectL; pThisDisplay->pGLInfo->dwOverlayRectR = pThisDisplay->OverlayDstRectR; pThisDisplay->pGLInfo->dwOverlayRectT = pThisDisplay->OverlayDstRectT; pThisDisplay->pGLInfo->dwOverlayRectB = pThisDisplay->OverlayDstRectB; if ( pThisDisplay->OverlayDstColourKey != CLR_INVALID ) { // update the alpha channel UpdateAlphaOverlay ( pThisDisplay ); pThisDisplay->OverlayUpdateCountdown = OVERLAY_UPDATE_WAIT; } // Do the update itself. P3TestDrawOverlay ( pThisDisplay, psopd->lpDDSrcSurface, FALSE ); pThisDisplay->bOverlayUpdatedThisVbl = (DWORD)TRUE; // And tell the world about it DISPDBG((DBGLVL,"** In SetOverlayPosition32")); DISPDBG((DBGLVL,"** ...Dst rect %d,%d -> %d,%d", pThisDisplay->OverlayDstRectL, pThisDisplay->OverlayDstRectT, pThisDisplay->OverlayDstRectR, pThisDisplay->OverlayDstRectB )); psopd->ddRVal = DD_OK; return DDHAL_DRIVER_HANDLED; } /**************************************************************************** * * LPRGNDATA GetOverlayVisibleRects ( P3_THUNKEDDATA* pThisDisplay ); * * In: * P3_THUNKEDDATA* pThisDisplay; This display's pointer * * Out: * LPRGNDATA; A pointer to the list of rects. * * Notes: * Returns a pointer to a list of rects that shows the visible * sections of the currently overlaid surface. This list is clipped by * the overlay's intended rectange, so no other bounds checking needs to * be done. * Note that the memory returned is private and may only be read by * other functions. The actual memory is owned by * pThisDisplay->OverlayClipRgnMem, and should only be changed by this * function (or freed in selected other places). The memory may change * every time this function is called, or when various other overlay * functions are called. * ***************************************************************************/ LPRGNDATA GetOverlayVisibleRects ( P3_THUNKEDDATA* pThisDisplay ) { // Use any clipper available. LPDDRAWI_DDRAWCLIPPER_INT lpDDIClipper; HRESULT hRes; int ClipSize; RECT rBound; rBound.left = pThisDisplay->OverlayDstRectL; rBound.right = pThisDisplay->OverlayDstRectR; rBound.top = pThisDisplay->OverlayDstRectT; rBound.bottom = pThisDisplay->OverlayDstRectB; // No WinWatch. Try doing an immediate call. lpDDIClipper = NULL; if ( ((LPDDRAWI_DDRAWSURFACE_LCL)pThisDisplay->OverlayDstSurfLcl) != NULL ) { if ( ((LPDDRAWI_DDRAWSURFACE_LCL)pThisDisplay->OverlayDstSurfLcl)->lpSurfMore != NULL ) { lpDDIClipper = ((LPDDRAWI_DDRAWSURFACE_LCL)pThisDisplay->OverlayDstSurfLcl)->lpSurfMore->lpDDIClipper; } } if ( lpDDIClipper != NULL ) { #ifdef __cplusplus hRes = ((IDirectDrawClipper*)(lpDDIClipper->lpVtbl))->GetClipList (&rBound, NULL, (unsigned long*)&ClipSize ); #else hRes = ((IDirectDrawClipperVtbl *)(lpDDIClipper->lpVtbl))->GetClipList ( (IDirectDrawClipper *)lpDDIClipper, &rBound, NULL, &ClipSize ); #endif if ( hRes == DD_OK ) { // Reallocate if need be. if ( ClipSize > (int)pThisDisplay->OverlayClipRgnMemSize ) { if (pThisDisplay->OverlayClipRgnMem != 0 ) { HEAP_FREE ((void *)pThisDisplay->OverlayClipRgnMem); pThisDisplay->OverlayClipRgnMem = 0; } pThisDisplay->OverlayClipRgnMem = (ULONG_PTR)HEAP_ALLOC (0, ClipSize, ALLOC_TAG_DX(F)); if ( (void *)pThisDisplay->OverlayClipRgnMem == NULL ) { DISPDBG((ERRLVL,"ERROR: Flip32: Could not allocate heap memory for clip region")); pThisDisplay->OverlayClipRgnMemSize = 0; return ( NULL ); } else { pThisDisplay->OverlayClipRgnMemSize = ClipSize; } } if ( (void *)pThisDisplay->OverlayClipRgnMem != NULL ) { // OK, got some good memory. #ifdef __cplusplus hRes = ((IDirectDrawClipper*)(lpDDIClipper->lpVtbl))->GetClipList (&rBound, (LPRGNDATA)pThisDisplay->OverlayClipRgnMem, (unsigned long*)&ClipSize ); #else hRes = ((IDirectDrawClipperVtbl *)(lpDDIClipper->lpVtbl))->GetClipList ( (IDirectDrawClipper *)lpDDIClipper, &rBound, (LPRGNDATA)pThisDisplay->OverlayClipRgnMem, &ClipSize ); #endif if ( hRes != DD_OK ) { DISPDBG((ERRLVL,"ERROR: Flip32: GetClipList failed.")); return ( NULL ); } else { LPRECT lpCurRect; RECT rBound; int NumRects; LPRGNDATA lpRgn; // Adjust their bounding rect so it actually does bound all the // rects. lpRgn = (LPRGNDATA)pThisDisplay->OverlayClipRgnMem; lpCurRect = (LPRECT)lpRgn->Buffer; NumRects = lpRgn->rdh.nCount; if ( NumRects > 0 ) { rBound = *lpCurRect; NumRects--; lpCurRect++; while ( NumRects > 0 ) { if ( rBound.left > lpCurRect->left ) { rBound.left = lpCurRect->left; } if ( rBound.top > lpCurRect->top ) { rBound.top = lpCurRect->top; } if ( rBound.right < lpCurRect->right ) { rBound.right = lpCurRect->right; } if ( rBound.bottom < lpCurRect->bottom ) { rBound.bottom = lpCurRect->bottom; } NumRects--; lpCurRect++; } #if DBG // Were the two bounding rectangles the same? if ( ( rBound.left != lpRgn->rdh.rcBound.left ) || ( rBound.right != lpRgn->rdh.rcBound.right ) || ( rBound.top != lpRgn->rdh.rcBound.top ) || ( rBound.bottom != lpRgn->rdh.rcBound.bottom ) ) { DISPDBG((DBGLVL,"GetOverlayVisibleRects: area bounding box does not actually bound!")); DISPDBG((DBGLVL,"My bounding rect %d,%d->%d,%d", rBound.left, rBound.top, rBound.right, rBound.bottom )); DISPDBG((DBGLVL,"Their bounding rect %d,%d->%d,%d", lpRgn->rdh.rcBound.left, lpRgn->rdh.rcBound.top, lpRgn->rdh.rcBound.right, lpRgn->rdh.rcBound.bottom )); } #endif lpRgn->rdh.rcBound = rBound; // Phew - we finally got a clip region. return ( (LPRGNDATA)pThisDisplay->OverlayClipRgnMem ); } else { // No cliplist. return ( NULL ); } } } else { return ( NULL ); } } else { return ( NULL ); } } return ( NULL ); } /**************************************************************************** * * DWORD GLDD__Autoflip_Overlay ( void ); * * In: * None. * * Out: * Error code: * GLDD_AUTO_RET_DID_UPDATE = no error - did update. * GLDD_AUTO_RET_ERR_GENERAL = general error. * GLDD_AUTO_RET_ERR_NO_OVERLAY = no autoflipping overlay(s). * * Notes: * This is called by the Demon helper program that sits waiting for * video-in VBLANKS, then calls this. * This flips the current overlay if it is marked as autoflipping. If * there is such an overlay, it returns 0, otherwise it returns 1. * ***************************************************************************/ DWORD CALLBACK __VD_AutoflipOverlay ( void ) { P3_THUNKEDDATA* pThisDisplay; LPDDRAWI_DIRECTDRAW_GBL lpDD; LPDDRAWI_DDRAWSURFACE_LCL pCurSurf; DDHAL_FLIPVPORTDATA ddhFVPD; // This is hard-coded and doesn't on work multi-monitors. // But then nothing does, so... pThisDisplay = g_pDriverData; DISPDBG((DBGLVL,"**In __VD_AutoflipOverlay")); if ( pThisDisplay->VidPort.bActive ) { // Video port is active. // Find the buffer to show. pCurSurf = pThisDisplay->VidPort.lpSurf [ pThisDisplay->VidPort.dwCurrentHostFrame ]; if ( pCurSurf == NULL ) { DISPDBG((WRNLVL,"ERROR:__VD_AutoflipOverlay: pCurSurf is NULL.")); return ( GLDD_AUTO_RET_ERR_NO_OVERLAY ); } if ( pCurSurf->lpGbl == NULL ) { DISPDBG((WRNLVL,"ERROR:__VD_AutoflipOverlay: lpGbl is NULL.")); return ( GLDD_AUTO_RET_ERR_GENERAL ); } lpDD = pCurSurf->lpGbl->lpDD; if ( lpDD == NULL ) { DISPDBG((WRNLVL,"ERROR:__VD_AutoflipOverlay: lpDD is NULL.")); return ( GLDD_AUTO_RET_ERR_GENERAL ); } DISPDBG((DBGLVL,"__VD_AutoflipOverlay: GetDriverLock succeeded.")); // Find the current front surface. pCurSurf = pThisDisplay->VidPort.lpSurf [ pThisDisplay->VidPort.dwCurrentHostFrame ]; P3TestDrawOverlay ( pThisDisplay, pCurSurf, TRUE ); pThisDisplay->bOverlayFlippedThisVbl = (DWORD)TRUE; // And then flip. // Fake up an LPDDHAL_FLIPVPORTDATA. // Only item ever used is lpDD. g_bFlipVideoPortDoingAutoflip = TRUE; ddhFVPD.lpDD = pCurSurf->lpSurfMore->lpDD_lcl; DdFlipVideoPort ( &ddhFVPD ); g_bFlipVideoPortDoingAutoflip = FALSE; return ( GLDD_AUTO_RET_DID_UPDATE ); } else { DISPDBG((DBGLVL,"ERROR:__VD_AutoflipOverlay: video port not active.")); return ( GLDD_AUTO_RET_ERR_NO_OVERLAY ); } } /**************************************************************************** * * DWORD __VD_AutoupdateOverlay ( void ); * * In: * None. * * Out: * Error code: * GLDD_AUTO_RET_NO_UPDATE = no need to do update. * GLDD_AUTO_RET_DID_UPDATE = did update. * GLDD_AUTO_RET_ERR_GENERAL = general error. * GLDD_AUTO_RET_ERR_NO_OVERLAY = no standard overlay(s). * * Notes: * This is called by the Demon helper program that sits waiting for * monitor VBLANKS, then calls this. * This checks any non-autoflipping overlay(s), and if they have not * been flipped or updated this VBL, it redraws them. Then it resets the * VBL flags. * ***************************************************************************/ DWORD CALLBACK __VD_AutoupdateOverlay ( void ) { P3_THUNKEDDATA* pThisDisplay; LPDDRAWI_DIRECTDRAW_GBL lpDD; LPDDRAWI_DDRAWSURFACE_LCL pCurSurf; DWORD iRet; // This is hard-coded and doesn't on work multi-monitors. // But then nothing does, so... pThisDisplay = g_pDriverData; if ( pThisDisplay->VidPort.bActive ) { // Video port is active. DISPDBG((WRNLVL,"ERROR:__VD_AutoupdateOverlay: video port is active.")); return ( GLDD_AUTO_RET_ERR_NO_OVERLAY ); } else { // Find the buffer to show. pCurSurf = (LPDDRAWI_DDRAWSURFACE_LCL)pThisDisplay->OverlaySrcSurfLcl; if ( pCurSurf == NULL ) { DISPDBG((WRNLVL,"ERROR:__VD_AutoupdateOverlay: pCurSurf is NULL.")); return ( GLDD_AUTO_RET_ERR_NO_OVERLAY ); } if ( pCurSurf->lpGbl == NULL ) { DISPDBG((WRNLVL,"ERROR:__VD_AutoupdateOverlay: lpGbl is NULL.")); return ( GLDD_AUTO_RET_ERR_NO_OVERLAY ); } lpDD = pCurSurf->lpGbl->lpDD; if ( lpDD == NULL ) { DISPDBG((WRNLVL,"ERROR:__VD_AutoupdateOverlay: lpDD is NULL.")); return ( GLDD_AUTO_RET_ERR_GENERAL ); } // See if the overlay needs showing. if ( pThisDisplay->bOverlayFlippedThisVbl || pThisDisplay->bOverlayUpdatedThisVbl ) { // Already done. pThisDisplay->bOverlayFlippedThisVbl = FALSE; pThisDisplay->bOverlayUpdatedThisVbl = FALSE; iRet = GLDD_AUTO_RET_NO_UPDATE; } else { // OK, draw this. P3TestDrawOverlay ( pThisDisplay, pCurSurf, TRUE ); // And clear the flags. pThisDisplay->bOverlayFlippedThisVbl = FALSE; pThisDisplay->bOverlayUpdatedThisVbl = FALSE; iRet = GLDD_AUTO_RET_DID_UPDATE; } return ( iRet ); } } /**************************************************************************** * * void DrawOverlay ( P3_THUNKEDDATA* pThisDisplay, * LPDDRAWI_DDRAWSURFACE_LCL lpSurfOverlay, * BOOL bSpeed ); * * In: * P3_THUNKEDDATA* pThisDisplay; This display's pointer * LPDDRAWI_DDRAWSURFACE_LCL lpSurfOverlay; The overlay surface to draw. * BOOL bSpeed; TRUE if this is a speedy call. * * Out: * None. * * Notes: * Takes the data in pThisDisplay and draws lpSurfOverlay onto * its overlayed surface. All the other data comes from lpSurfOverlay. * This allows you to call this from Flip32() without kludging the source * surface pointer. * This will find the cliprect list of the clipper attached to the * overlaid surface, clipped by the overlay rectangle.. If there is no * clipper, it just uses the rectangle of the overlay. * The next operation depends on which colour keys are set: * If no colour keys are set, the rects are just blitted on. * If the destination colour key is set, three blits are done. * The first stretches the YUV buffer to its final size. The second converts * any of the given colour key to set its alpha bits. The third puts * the overlay surface onto the screen where the alpha bits have been set, * settign the alpha bits as it does so. * If you cross your fingers and wish very very hard, this might * actually work. It depends on nothing writing anything but 0 to the * alpha bits, and on having alpha bits in the first place. * bSpeed will be TRUE if we are aiming for out-and-out speed, * otherwise the aim is to look pretty with as few artefacts as possible. * Generally, speed tests are done single-buffered, so a call from * Unlock32() will pass TRUE. Pretty tests are done with single-buffering, * so Flip32() will pass FALSE. This is only a general guide, and some * apps don't know about double-buffering at all. Such is life. * ***************************************************************************/ void DrawOverlay ( P3_THUNKEDDATA* pThisDisplay, LPDDRAWI_DDRAWSURFACE_LCL lpSurfOverlay, BOOL bSpeed ) { RECTL rOverlay; RECTL rTemp; RECTL rFB; LPDDRAWI_DDRAWSURFACE_LCL pOverlayLcl; LPDDRAWI_DDRAWSURFACE_GBL pOverlayGbl; DDRAWI_DDRAWSURFACE_LCL TempLcl; DDRAWI_DDRAWSURFACE_GBL TempGbl; LPDDRAWI_DDRAWSURFACE_LCL pFBLcl; LPDDRAWI_DDRAWSURFACE_GBL pFBGbl; P3_SURF_FORMAT* pFormatOverlay; P3_SURF_FORMAT* pFormatTemp; P3_SURF_FORMAT* pFormatFB; DWORD localfpVidMem; LONG localPitch; LPDDRAWI_DIRECTDRAW_GBL lpDD; DWORD dwColourKeyValue; DWORD dwAlphaMask; DWORD windowBaseOverlay; DWORD windowBaseFB; DWORD windowBaseTemp; float OffsetX, OffsetY; float ScaleX, ScaleY; float fTemp; int NumRects; LPRECT lpCurRect; LPRGNDATA lpRgn; DWORD dwCurrentIndex, dwStartTime; DWORD xScale; DWORD yScale; DWORD DestWidth; DWORD DestHeight; DWORD SourceWidth; DWORD SourceHeight; DWORD LowerBound; DWORD UpperBound; RECT TempRect; P3_DMA_DEFS(); // Find the clipping rectangles for the overlay. lpRgn = GetOverlayVisibleRects ( pThisDisplay ); if ( lpRgn != NULL ) { pOverlayLcl = lpSurfOverlay; pFBLcl = (LPDDRAWI_DDRAWSURFACE_LCL)pThisDisplay->OverlayDstSurfLcl; lpDD = lpSurfOverlay->lpGbl->lpDD; // Find the scale and offset from screen rects to overlay rects. ScaleX = (float)( pThisDisplay->OverlaySrcRectR - pThisDisplay->OverlaySrcRectL ) / (float)( pThisDisplay->OverlayDstRectR - pThisDisplay->OverlayDstRectL ); ScaleY = (float)( pThisDisplay->OverlaySrcRectB - pThisDisplay->OverlaySrcRectT ) / (float)( pThisDisplay->OverlayDstRectB - pThisDisplay->OverlayDstRectT ); OffsetX = ( (float)pThisDisplay->OverlaySrcRectL / ScaleX ) - (float)pThisDisplay->OverlayDstRectL; OffsetY = ( (float)pThisDisplay->OverlaySrcRectT / ScaleY ) - (float)pThisDisplay->OverlayDstRectT; rFB.left = lpRgn->rdh.rcBound.left; rFB.right = lpRgn->rdh.rcBound.right; rFB.top = lpRgn->rdh.rcBound.top; rFB.bottom = lpRgn->rdh.rcBound.bottom; // Find the size of the screen bounding box. if ( lpRgn->rdh.rcBound.left != (int)pThisDisplay->OverlayDstRectL ) { fTemp = ( ( (float)lpRgn->rdh.rcBound.left + OffsetX ) * ScaleX + 0.499f ); myFtoi ( (int*)&(rOverlay.left), fTemp ); } else { rOverlay.left = (int)pThisDisplay->OverlaySrcRectL; } if ( lpRgn->rdh.rcBound.right != (int)pThisDisplay->OverlayDstRectR ) { fTemp = ( ( (float)lpRgn->rdh.rcBound.right + OffsetX ) * ScaleX + 0.499f ); myFtoi ( (int*)&(rOverlay.right), fTemp ); } else { rOverlay.right = (int)pThisDisplay->OverlaySrcRectR; } if ( lpRgn->rdh.rcBound.top != (int)pThisDisplay->OverlayDstRectT ) { fTemp = ( ( (float)lpRgn->rdh.rcBound.top + OffsetY ) * ScaleY + 0.499f ); myFtoi ( (int*)&(rOverlay.top), fTemp ); } else { rOverlay.top = (int)pThisDisplay->OverlaySrcRectT; } if ( lpRgn->rdh.rcBound.bottom = (int)pThisDisplay->OverlayDstRectB ) { fTemp = ( ( (float)lpRgn->rdh.rcBound.bottom + OffsetY ) * ScaleY + 0.499f ); myFtoi ( (int*)&(rOverlay.bottom), fTemp ); } else { rOverlay.bottom = pThisDisplay->OverlaySrcRectB; } // Sync with the specific source surface. // Videoport playing? if ( ( pThisDisplay->VidPort.bActive == TRUE ) && ( ( pOverlayLcl->ddsCaps.dwCaps & DDSCAPS_VIDEOPORT ) != 0 ) ) { dwStartTime = timeGetTime(); while ( TRUE ) { dwCurrentIndex = READ_GLINT_CTRL_REG(VSAVideoAddressIndex); if (pThisDisplay->VidPort.dwCurrentHostFrame == dwCurrentIndex) { // If the videoport is not stuck we are still drawing if (!__VD_CheckVideoPortStatus(pThisDisplay, FALSE)) { break; } } else { break; } // Have we timed out? if ( ( timeGetTime() - dwStartTime ) > OVERLAY_VIDEO_PORT_TIMEOUT ) { return; } } } else { // Not a videoport blit, so wait for the framebuffer flip // status to be good. //@@BEGIN_DDKSPLIT // Not actually sure if we want this in or not. //@@END_DDKSPLIT { HRESULT ddrval; do { ddrval = _DX_QueryFlipStatus(pThisDisplay, pFBLcl->lpGbl->fpVidMem, TRUE ); } while ( ddrval != DD_OK ); } } if ( pThisDisplay->OverlayDstColourKey != CLR_INVALID ) { // This is destination colourkeyed. rTemp.left = 0; rTemp.right = rFB.right - rFB.left; rTemp.top = 0; rTemp.bottom = rFB.bottom - rFB.top; if ( pThisDisplay->OverlayUpdateCountdown != 0 ) { pThisDisplay->OverlayUpdateCountdown -= OVERLAY_DRAWOVERLAY_SPEED; if ( !bSpeed ) { // This is a pretty call, not a fast one. pThisDisplay->OverlayUpdateCountdown -= ( OVERLAY_DRAWOVERLAY_PRETTY - OVERLAY_DRAWOVERLAY_SPEED ); } if ( ( (signed int)pThisDisplay->OverlayUpdateCountdown ) <= 0 ) { // Update the overlay. UpdateAlphaOverlay ( pThisDisplay ); // If you set this to 0, the overlay will never update again // until a SetOverlayPosition() or UpdateOverlay32() // Otherwise, set it to a positive value to update every now // and then. pThisDisplay->OverlayUpdateCountdown = OVERLAY_CYCLE_WAIT; } } VALIDATE_MODE_AND_STATE(pThisDisplay); // First stop dual cursor accesses // Must be done before switching to DD context. STOP_SOFTWARE_CURSOR(pThisDisplay); // Switch to DirectDraw context DDRAW_OPERATION(pContext, pThisDisplay); DISPDBG((DBGLVL,"** In DrawOverlay")); pOverlayGbl = pOverlayLcl->lpGbl; pFBGbl = pFBLcl->lpGbl; pFormatOverlay = _DD_SUR_GetSurfaceFormat(pOverlayLcl); pFormatFB = _DD_SUR_GetSurfaceFormat(pFBLcl); // Temp buffer will be same format as framebuffer. pFormatTemp = pFormatFB; DISPDBG((DBGLVL, "Overlay Surface:")); DBGDUMP_DDRAWSURFACE_LCL(DBGLVL, pOverlayLcl); DISPDBG((DBGLVL, "FB Surface:")); DBGDUMP_DDRAWSURFACE_LCL(DBGLVL, pFBLcl); dwColourKeyValue = pThisDisplay->OverlayDstColourKey; switch ( pThisDisplay->bPixShift ) { case GLINTDEPTH16: if ( pThisDisplay->ddpfDisplay.dwRBitMask == 0x7C00 ) { // 5551 format, as it should be. dwAlphaMask = 0x8000; } else { // 565 format. Oops. DISPDBG((WRNLVL, "** DrawOverlay error: called for a 565 surface")); return; } break; case GLINTDEPTH32: dwAlphaMask = 0xff000000; break; case GLINTDEPTH8: case GLINTDEPTH24: default: DISPDBG((WRNLVL, "** DrawOverlay error: called for an 8, 24 or unknown surface bPixShift=%d", pThisDisplay->bPixShift)); return; break; } // dwColourKeyValue &= ~dwAlphaMask; localfpVidMem = pThisDisplay->OverlayTempSurf.VidMem; localPitch = pThisDisplay->OverlayTempSurf.Pitch; if ( (void *)localfpVidMem == NULL ) { // Nothing has been reserved for us! Panic stations! DISPDBG((ERRLVL,"ERROR: DrawOverlay has no temporary surface allocated.")); return; } if ( localPitch < ( ( rTemp.right - rTemp.left ) << ( DDSurf_GetChipPixelSize(pFBLcl) ) ) ) { // Reserved pitch is too small! Panic stations! DISPDBG((WRNLVL,"DrawOverlay has left,right %d,%d, and overlay has left,right %d,%d", rFB.left, rFB.right, pThisDisplay->OverlayDstRectL, pThisDisplay->OverlayDstRectR )); DISPDBG((WRNLVL,"ERROR: DrawOverlay has pitch %d and should be at least %d", localPitch, ( ( rTemp.right - rTemp.left ) << ( DDSurf_GetChipPixelSize(pFBLcl) ) ) )); DISPDBG((ERRLVL,"ERROR: DrawOverlay has pitch too small to be right.")); return; } // Set the surface up. TempLcl = *pFBLcl; TempGbl = *(pFBLcl->lpGbl); TempLcl.lpGbl = &TempGbl; TempGbl.fpVidMem = localfpVidMem; DDSurf_Pitch(&TempLcl) = localPitch; // get bpp and pitches for surfaces. windowBaseOverlay = __VD_PixelOffsetFromMemoryBase(pThisDisplay, pOverlayLcl); windowBaseFB = __VD_PixelOffsetFromMemoryBase(pThisDisplay, pFBLcl); windowBaseTemp = __VD_PixelOffsetFromMemoryBase(pThisDisplay, &TempLcl); // Do the colourspace conversion and stretch/shrink of the overlay { DestWidth = rTemp.right - rTemp.left; DestHeight = rTemp.bottom - rTemp.top; SourceWidth = rOverlay.right - rOverlay.left; SourceHeight = rOverlay.bottom - rOverlay.top; xScale = (SourceWidth << 20) / DestWidth; yScale = (SourceHeight << 20) / DestHeight; P3_DMA_GET_BUFFER(); P3_ENSURE_DX_SPACE(80); WAIT_FIFO(40); SEND_P3_DATA(DitherMode, (COLOR_MODE << PM_DITHERMODE_COLORORDER) | (SURFFORMAT_FORMAT_BITS(pFormatTemp) << PM_DITHERMODE_COLORFORMAT) | (SURFFORMAT_FORMATEXTENSION_BITS(pFormatTemp) << PM_DITHERMODE_COLORFORMATEXTENSION) | (1 << PM_DITHERMODE_ENABLE) | (2 << PM_DITHERMODE_FORCEALPHA) | (1 << PM_DITHERMODE_DITHERENABLE)); SEND_P3_DATA(FBReadPixel, DDSurf_GetChipPixelSize((&TempLcl)) ); SEND_P3_DATA(FBWindowBase, windowBaseTemp); // set no read of source. SEND_P3_DATA(FBReadMode, PACKED_PP_LOOKUP(DDSurf_GetPixelPitch((&TempLcl)))); SEND_P3_DATA(LogicalOpMode, __PERMEDIA_DISABLE); // set base of source SEND_P3_DATA(TextureBaseAddress, windowBaseOverlay); SEND_P3_DATA(TextureAddressMode, PM_TEXADDRESSMODE_ENABLE(__PERMEDIA_ENABLE)); SEND_P3_DATA(TextureColorMode, PM_TEXCOLORMODE_ENABLE(__PERMEDIA_ENABLE) | PM_TEXCOLORMODE_APPLICATIONMODE(__GLINT_TEXCOLORMODE_APPLICATION_COPY)); SEND_P3_DATA(TextureReadMode, PM_TEXREADMODE_ENABLE(__PERMEDIA_ENABLE) | PM_TEXREADMODE_FILTER(__PERMEDIA_DISABLE) | PM_TEXREADMODE_WIDTH(11) | PM_TEXREADMODE_HEIGHT(11) ); SEND_P3_DATA(TextureMapFormat, PACKED_PP_LOOKUP(DDSurf_GetPixelPitch(pOverlayLcl)) | (DDSurf_GetChipPixelSize(pOverlayLcl) << PM_TEXMAPFORMAT_TEXELSIZE) ); if ( pFormatOverlay->DeviceFormat == SURF_YUV422 ) { // Turn on the YUV unit SEND_P3_DATA(TextureDataFormat, PM_TEXDATAFORMAT_FORMAT(SURFFORMAT_FORMAT_BITS(pFormatOverlay)) | PM_TEXDATAFORMAT_FORMATEXTENSION(SURFFORMAT_FORMATEXTENSION_BITS(pFormatOverlay)) | PM_TEXDATAFORMAT_COLORORDER(INV_COLOR_MODE)); SEND_P3_DATA(YUVMode, 0x1); } else { SEND_P3_DATA(TextureDataFormat, PM_TEXDATAFORMAT_FORMAT(SURFFORMAT_FORMAT_BITS(pFormatOverlay)) | PM_TEXDATAFORMAT_FORMATEXTENSION(SURFFORMAT_FORMATEXTENSION_BITS(pFormatOverlay)) | PM_TEXDATAFORMAT_COLORORDER(COLOR_MODE)); // Shouldn't actually need this - it's the default setting. SEND_P3_DATA(YUVMode, 0x0); } SEND_P3_DATA(LogicalOpMode, 0); // set offset of source SEND_P3_DATA(SStart, rOverlay.left << 20); SEND_P3_DATA(TStart, rOverlay.top<< 20); SEND_P3_DATA(dSdx, xScale); SEND_P3_DATA(dSdyDom, 0); WAIT_FIFO(24); SEND_P3_DATA(dTdx, 0); SEND_P3_DATA(dTdyDom, yScale); /* * Render the rectangle */ SEND_P3_DATA(StartXDom, rTemp.left << 16); SEND_P3_DATA(StartXSub, rTemp.right << 16); SEND_P3_DATA(StartY, rTemp.top << 16); SEND_P3_DATA(dY, 1 << 16); SEND_P3_DATA(Count, rTemp.bottom - rTemp.top); SEND_P3_DATA(Render, __RENDER_TRAPEZOID_PRIMITIVE | __RENDER_TEXTURED_PRIMITIVE); SEND_P3_DATA(DitherMode, 0); // Turn off the YUV unit SEND_P3_DATA(YUVMode, 0x0); SEND_P3_DATA(TextureAddressMode, PM_TEXADDRESSMODE_ENABLE(__PERMEDIA_DISABLE)); SEND_P3_DATA(TextureColorMode, PM_TEXCOLORMODE_ENABLE(__PERMEDIA_DISABLE)); P3_DMA_COMMIT_BUFFER(); } // Blit the expanded overlay to the framebuffer, colourkeying off the alpha. { // Select anything with full alpha. LowerBound = 0xff000000; UpperBound = 0xffffffff; P3_DMA_GET_BUFFER(); P3_ENSURE_DX_SPACE(40); WAIT_FIFO(20); // don't need to twiddle the source (which is actually the framebuffer). SEND_P3_DATA(DitherMode,0); // Accept range, disable updates SEND_P3_DATA(YUVMode, (0x1 << 1)|0x20); // set a read of source. // Note - as we are enabling reads, we might have to do a WaitForCompleteion // (see the P2 Programmer's Reference Manual about the FBReamMode for more details. // but I think we should be OK - we are unlikely to have just written this data. SEND_P3_DATA(FBReadMode,(PACKED_PP_LOOKUP(DDSurf_GetPixelPitch((&TempLcl)))) | PM_FBREADMODE_READSOURCE(__PERMEDIA_ENABLE) ); SEND_P3_DATA(LogicalOpMode, __PERMEDIA_DISABLE); // set FB write point SEND_P3_DATA(FBWindowBase, windowBaseFB); // set up FBWrite mode. This _must_ be done after setting up FBReadMode. SEND_P3_DATA(FBWriteConfig,(PACKED_PP_LOOKUP(DDSurf_GetPixelPitch((pFBLcl))))); // offset the source point (point it at the temp thingie) SEND_P3_DATA(FBSourceOffset, windowBaseTemp - windowBaseFB - rFB.left - ( ( rFB.top * DDSurf_GetPixelPitch((&TempLcl)) ) ) ); // set base of source SEND_P3_DATA(TextureBaseAddress, windowBaseFB); SEND_P3_DATA(TextureAddressMode, PM_TEXADDRESSMODE_ENABLE(__PERMEDIA_ENABLE)); SEND_P3_DATA(TextureColorMode, PM_TEXCOLORMODE_ENABLE(__PERMEDIA_ENABLE) | PM_TEXCOLORMODE_APPLICATIONMODE(__GLINT_TEXCOLORMODE_APPLICATION_COPY)); SEND_P3_DATA(TextureReadMode, PM_TEXREADMODE_ENABLE(__PERMEDIA_ENABLE) | PM_TEXREADMODE_FILTER(__PERMEDIA_DISABLE) | PM_TEXREADMODE_WIDTH(11) | PM_TEXREADMODE_HEIGHT(11) ); SEND_P3_DATA(TextureDataFormat, PM_TEXDATAFORMAT_FORMAT(SURFFORMAT_FORMAT_BITS(pFormatFB)) | PM_TEXDATAFORMAT_FORMATEXTENSION(SURFFORMAT_FORMATEXTENSION_BITS(pFormatFB)) | PM_TEXDATAFORMAT_COLORORDER(COLOR_MODE)); SEND_P3_DATA(TextureMapFormat, ((PACKED_PP_LOOKUP(DDSurf_GetPixelPitch(pFBLcl)))) | (DDSurf_GetChipPixelSize(pFBLcl) << PM_TEXMAPFORMAT_TEXELSIZE) ); SEND_P3_DATA(ChromaLowerBound, LowerBound); SEND_P3_DATA(ChromaUpperBound, UpperBound); SEND_P3_DATA(dSdx, 1 << 20); SEND_P3_DATA(dSdyDom, 0); SEND_P3_DATA(dTdx, 0); SEND_P3_DATA(dTdyDom, 1 << 20); SEND_P3_DATA(dY, 1 << 16); lpCurRect = (LPRECT)lpRgn->Buffer; NumRects = lpRgn->rdh.nCount; while ( NumRects > 0 ) { P3_ENSURE_DX_SPACE(14); WAIT_FIFO(7); SEND_P3_DATA(SStart, lpCurRect->left << 20); SEND_P3_DATA(TStart, lpCurRect->top << 20); // SEND_P3_DATA(dSdx, 1 << 20); // SEND_P3_DATA(dSdyDom, 0); // SEND_P3_DATA(dTdx, 0); // SEND_P3_DATA(dTdyDom, 1 << 20); SEND_P3_DATA(StartXDom, lpCurRect->left << 16); SEND_P3_DATA(StartXSub, lpCurRect->right << 16); SEND_P3_DATA(StartY, lpCurRect->top << 16); // SEND_P3_DATA(dY, 1 << 16); SEND_P3_DATA(Count, lpCurRect->bottom - lpCurRect->top); SEND_P3_DATA(Render, __RENDER_TRAPEZOID_PRIMITIVE | __RENDER_TEXTURED_PRIMITIVE); // Next rect NumRects--; lpCurRect++; } P3_ENSURE_DX_SPACE(10); WAIT_FIFO(5); SEND_P3_DATA(DitherMode, 0); SEND_P3_DATA(YUVMode, 0x0); SEND_P3_DATA(TextureAddressMode, __PERMEDIA_DISABLE); SEND_P3_DATA(TextureColorMode, __PERMEDIA_DISABLE); SEND_P3_DATA(TextureReadMode, __PERMEDIA_DISABLE); P3_DMA_COMMIT_BUFFER(); } #ifdef WANT_DMA if (pThisDisplay->pGLInfo->InterfaceType == GLINT_DMA) { // If we have queued up a DMA, we must send it now. P3_DMA_DEFS(); P3_DMA_GET_BUFFER(); // Flush DMA buffer P3_DMA_FLUSH_BUFFER(); } #endif START_SOFTWARE_CURSOR(pThisDisplay); } else { // Not colourkeyed, so just blit directly to the screen. DISPDBG((DBGLVL,"** In DrawOverlay")); VALIDATE_MODE_AND_STATE(pThisDisplay); pOverlayGbl = pOverlayLcl->lpGbl; pFBGbl = pFBLcl->lpGbl; pFormatOverlay = _DD_SUR_GetSurfaceFormat(pOverlayLcl); pFormatFB = _DD_SUR_GetSurfaceFormat(pFBLcl); // Temp buffer will be same format as framebuffer. DISPDBG((DBGLVL, "Overlay Surface:")); DBGDUMP_DDRAWSURFACE_LCL(DBGLVL, pOverlayLcl); DISPDBG((DBGLVL, "FB Surface:")); DBGDUMP_DDRAWSURFACE_LCL(DBGLVL, pFBLcl); // First stop dual cursor accesses STOP_SOFTWARE_CURSOR(pThisDisplay); // Switch to DirectDraw context DDRAW_OPERATION(pContext, pThisDisplay); windowBaseOverlay = __VD_PixelOffsetFromMemoryBase(pThisDisplay, pOverlayLcl); windowBaseFB = __VD_PixelOffsetFromMemoryBase(pThisDisplay, pFBLcl); { P3_DMA_GET_BUFFER(); P3_ENSURE_DX_SPACE(70); WAIT_FIFO(16); SEND_P3_DATA(DitherMode, (COLOR_MODE << PM_DITHERMODE_COLORORDER) | (SURFFORMAT_FORMAT_BITS(pFormatFB) << PM_DITHERMODE_COLORFORMAT) | (SURFFORMAT_FORMATEXTENSION_BITS(pFormatFB) << PM_DITHERMODE_COLORFORMATEXTENSION) | (1 << PM_DITHERMODE_ENABLE) | (1 << PM_DITHERMODE_DITHERENABLE)); SEND_P3_DATA(FBReadPixel, DDSurf_GetChipPixelSize((pFBLcl)) ); SEND_P3_DATA(FBWindowBase, windowBaseFB); // set no read of source. SEND_P3_DATA(FBReadMode, PACKED_PP_LOOKUP(DDSurf_GetPixelPitch((pFBLcl)))); SEND_P3_DATA(LogicalOpMode, __PERMEDIA_DISABLE); // set base of source SEND_P3_DATA(TextureBaseAddress, windowBaseOverlay); SEND_P3_DATA(TextureAddressMode, PM_TEXADDRESSMODE_ENABLE(__PERMEDIA_ENABLE)); SEND_P3_DATA(TextureColorMode, PM_TEXCOLORMODE_ENABLE(__PERMEDIA_ENABLE) | PM_TEXCOLORMODE_APPLICATIONMODE(__GLINT_TEXCOLORMODE_APPLICATION_COPY)); SEND_P3_DATA(TextureReadMode, PM_TEXREADMODE_ENABLE(__PERMEDIA_ENABLE) | PM_TEXREADMODE_FILTER(__PERMEDIA_DISABLE) | PM_TEXREADMODE_WIDTH(11) | PM_TEXREADMODE_HEIGHT(11) ); SEND_P3_DATA(TextureMapFormat, PACKED_PP_LOOKUP(DDSurf_GetPixelPitch(pOverlayLcl)) | (DDSurf_GetChipPixelSize(pOverlayLcl) << PM_TEXMAPFORMAT_TEXELSIZE) ); if ( pFormatOverlay->DeviceFormat == SURF_YUV422 ) { // Turn on the YUV unit SEND_P3_DATA(TextureDataFormat, PM_TEXDATAFORMAT_FORMAT(SURFFORMAT_FORMAT_BITS(pFormatOverlay)) | PM_TEXDATAFORMAT_FORMATEXTENSION(SURFFORMAT_FORMATEXTENSION_BITS(pFormatOverlay)) | PM_TEXDATAFORMAT_COLORORDER(INV_COLOR_MODE)); SEND_P3_DATA(YUVMode, 0x1); } else { SEND_P3_DATA(TextureDataFormat, PM_TEXDATAFORMAT_FORMAT(SURFFORMAT_FORMAT_BITS(pFormatOverlay)) | PM_TEXDATAFORMAT_FORMATEXTENSION(SURFFORMAT_FORMATEXTENSION_BITS(pFormatOverlay)) | PM_TEXDATAFORMAT_COLORORDER(COLOR_MODE)); // Shouldn't actually need this - it's the default setting. SEND_P3_DATA(YUVMode, 0x0); } SEND_P3_DATA(LogicalOpMode, 0); // Constant values in the rectangle loop. SEND_P3_DATA(dSdyDom, 0); SEND_P3_DATA(dTdx, 0); SEND_P3_DATA(dY, 1 << 16); lpCurRect = (LPRECT)lpRgn->Buffer; NumRects = lpRgn->rdh.nCount; while ( NumRects > 0 ) { // Transform the source rect. fTemp = ( ( (float)lpCurRect->left + OffsetX ) * ScaleX + 0.499f ); myFtoi ( (int*)&(TempRect.left), fTemp ); fTemp = ( ( (float)lpCurRect->right + OffsetX ) * ScaleX + 0.499f ); myFtoi ( (int*)&(TempRect.right), fTemp ); fTemp = ( ( (float)lpCurRect->top + OffsetY ) * ScaleY + 0.499f ); myFtoi ( (int*)&(TempRect.top), fTemp ); fTemp = ( ( (float)lpCurRect->bottom + OffsetY ) * ScaleY + 0.499f ); myFtoi ( (int*)&(TempRect.bottom), fTemp ); xScale = ( ( TempRect.right - TempRect.left ) << 20) / ( lpCurRect->right - lpCurRect->left ); yScale = ( ( TempRect.bottom - TempRect.top ) << 20) / ( lpCurRect->bottom - lpCurRect->top ); P3_ENSURE_DX_SPACE(18); WAIT_FIFO(9); // set offset of source SEND_P3_DATA(SStart, TempRect.left << 20); SEND_P3_DATA(TStart, TempRect.top << 20); SEND_P3_DATA(dSdx, xScale); // SEND_P3_DATA(dSdyDom, 0); // SEND_P3_DATA(dTdx, 0); SEND_P3_DATA(dTdyDom, yScale); SEND_P3_DATA(StartXDom, lpCurRect->left << 16); SEND_P3_DATA(StartXSub, lpCurRect->right << 16); SEND_P3_DATA(StartY, lpCurRect->top << 16); // SEND_P3_DATA(dY, 1 << 16); SEND_P3_DATA(Count, lpCurRect->bottom - lpCurRect->top); SEND_P3_DATA(Render, __RENDER_TRAPEZOID_PRIMITIVE | __RENDER_TEXTURED_PRIMITIVE); // Next rect NumRects--; lpCurRect++; } P3_ENSURE_DX_SPACE(10); WAIT_FIFO(5); SEND_P3_DATA(DitherMode, 0); // Turn off YUV conversion. if ( pFormatOverlay->DeviceFormat == SURF_YUV422 ) { SEND_P3_DATA(YUVMode, 0x0); } SEND_P3_DATA(TextureAddressMode, __PERMEDIA_DISABLE); SEND_P3_DATA(TextureColorMode, __PERMEDIA_DISABLE); SEND_P3_DATA(TextureReadMode, __PERMEDIA_DISABLE); P3_DMA_COMMIT_BUFFER(); } #ifdef WANT_DMA if (pThisDisplay->pGLInfo->InterfaceType == GLINT_DMA) { // If we have queued up a DMA, we must send it now. P3_DMA_DEFS(); P3_DMA_GET_BUFFER(); if( (DWORD)dmaPtr != pThisDisplay->pGLInfo->DMAPartition[pThisDisplay->pGLInfo->CurrentPartition].VirtAddr ) { // Flush DMA buffer P3_DMA_FLUSH_BUFFER(); } } #endif START_SOFTWARE_CURSOR(pThisDisplay); } // And that's all. } return; } /**************************************************************************** * * void UpdateAlphaOverlay ( P3_THUNKEDDATA* pThisDisplay ); * * In: * P3_THUNKEDDATA* pThisDisplay; This display's pointer * * Out: * None. * * Notes: * Takes the data in pThisDisplay and changes everything of the right * colourkey to black with a full alpha, ready for calls to DrawOverlay() * ***************************************************************************/ void UpdateAlphaOverlay ( P3_THUNKEDDATA* pThisDisplay ) { RECTL rFB; LPDDRAWI_DDRAWSURFACE_LCL pFBLcl; LPDDRAWI_DDRAWSURFACE_GBL pFBGbl; P3_SURF_FORMAT* pFormatFB; LPDDRAWI_DIRECTDRAW_GBL lpDD; DWORD dwColourKeyValue; DWORD dwAlphaMask; DWORD windowBaseFB; LONG lPixPitchFB; DWORD LowerBound; DWORD UpperBound; P3_DMA_DEFS(); REPORTSTAT(pThisDisplay, ST_Blit, 1); rFB.left = (LONG)pThisDisplay->OverlayDstRectL; rFB.right = (LONG)pThisDisplay->OverlayDstRectR; rFB.top = (LONG)pThisDisplay->OverlayDstRectT; rFB.bottom = (LONG)pThisDisplay->OverlayDstRectB; pFBLcl = (LPDDRAWI_DDRAWSURFACE_LCL)pThisDisplay->OverlayDstSurfLcl; DISPDBG((DBGLVL,"** In UpdateAlphaOverlay")); VALIDATE_MODE_AND_STATE(pThisDisplay); pFBGbl = pFBLcl->lpGbl; pFormatFB = _DD_SUR_GetSurfaceFormat(pFBLcl); DISPDBG((DBGLVL, "FB Surface:")); DBGDUMP_DDRAWSURFACE_LCL(10, pFBLcl); dwColourKeyValue = pThisDisplay->OverlayDstColourKey; switch ( pThisDisplay->bPixShift ) { case GLINTDEPTH16: if ( pThisDisplay->ddpfDisplay.dwRBitMask == 0x7C00 ) { // 5551 format, as it should be. dwAlphaMask = 0x8000; } else { // 565 format. Oops. DISPDBG((WRNLVL, "** DrawOverlay error: called for a 565 surface")); return; } break; case GLINTDEPTH32: dwAlphaMask = 0xff000000; break; case GLINTDEPTH8: case GLINTDEPTH24: default: DISPDBG((WRNLVL, "** DrawOverlay error: called for an 8, 24 or unknown surface bPixShift=%d", pThisDisplay->bPixShift)); return; break; } dwColourKeyValue &= ~dwAlphaMask; lpDD = pFBLcl->lpGbl->lpDD; // First stop dual cursor accesses STOP_SOFTWARE_CURSOR(pThisDisplay); // Switch to DirectDraw context DDRAW_OPERATION(pContext, pThisDisplay); // get bpp and pitches for surfaces. lPixPitchFB = pFBGbl->lPitch; windowBaseFB = (pFBGbl->fpVidMem - pThisDisplay->dwScreenFlatAddr) >> DDSurf_GetPixelShift(pFBLcl); lPixPitchFB = lPixPitchFB >> DDSurf_GetPixelShift(pFBLcl); // Do the colourkey(no alpha) to colourkey+alpha blit. DISPDBG((DBGLVL, "Source Surface:")); DBGDUMP_DDRAWSURFACE_LCL(DBGLVL, pFBLcl); LowerBound = dwColourKeyValue; UpperBound = dwColourKeyValue; switch (pFormatFB->DeviceFormat) { case SURF_5551_FRONT: LowerBound = FORMAT_5551_32BIT_BGR(LowerBound); UpperBound = FORMAT_5551_32BIT_BGR(UpperBound); LowerBound = LowerBound & 0x00F8F8F8; // Account for 'missing bits' UpperBound = UpperBound & 0x00FFFFFF; // and vape any alpha UpperBound = UpperBound | 0x00070707; break; case SURF_8888: LowerBound = FORMAT_8888_32BIT_BGR(LowerBound); UpperBound = FORMAT_8888_32BIT_BGR(UpperBound); LowerBound = LowerBound & 0x00FFFFFF; // Bin any alpha. UpperBound = UpperBound & 0x00FFFFFF; break; default: DISPDBG((WRNLVL,"** DrawOverlay: invalid source pixel format passed (DeviceFormat=%d)",pFormatFB->DeviceFormat)); break; } P3_DMA_GET_BUFFER(); P3_ENSURE_DX_SPACE(70); WAIT_FIFO(36); // if (DDSurf_GetChipPixelSize(pSrcLcl) != __GLINT_8BITPIXEL) // { SEND_P3_DATA(DitherMode, (COLOR_MODE << PM_DITHERMODE_COLORORDER) | (SURFFORMAT_FORMAT_BITS(pFormatFB) << PM_DITHERMODE_COLORFORMAT) | (SURFFORMAT_FORMATEXTENSION_BITS(pFormatFB) << PM_DITHERMODE_COLORFORMATEXTENSION) | (1 << PM_DITHERMODE_ENABLE)); // } SEND_P3_DATA(FBReadPixel, pThisDisplay->bPixShift); // Accept range, disable updates SEND_P3_DATA(YUVMode, (0x1 << 1)|0x20); SEND_P3_DATA(FBWindowBase, windowBaseFB); // set the colour to be written (rather than the texture colour) // use the colour key with alpha set. SEND_P3_DATA(ConstantColor, ( LowerBound | 0xff000000 ) ); // Enable colour, disable DDAs. SEND_P3_DATA(ColorDDAMode, 0x1); // Disable reads of FBsource or FBdest - all data comes from the texture unit. SEND_P3_DATA(FBReadMode,(PACKED_PP_LOOKUP(DDSurf_GetPixelPitch(pFBLcl)))); SEND_P3_DATA(LogicalOpMode, __PERMEDIA_DISABLE); // set base of source SEND_P3_DATA(TextureBaseAddress, windowBaseFB); SEND_P3_DATA(TextureAddressMode, PM_TEXADDRESSMODE_ENABLE(__PERMEDIA_ENABLE)); SEND_P3_DATA(TextureColorMode, PM_TEXCOLORMODE_ENABLE(__PERMEDIA_ENABLE) | PM_TEXCOLORMODE_APPLICATIONMODE(__GLINT_TEXCOLORMODE_APPLICATION_COPY)); SEND_P3_DATA(TextureReadMode, PM_TEXREADMODE_ENABLE(__PERMEDIA_ENABLE) | PM_TEXREADMODE_FILTER(__PERMEDIA_DISABLE) | PM_TEXREADMODE_WIDTH(11) | PM_TEXREADMODE_HEIGHT(11) ); SEND_P3_DATA(TextureDataFormat, PM_TEXDATAFORMAT_FORMAT(SURFFORMAT_FORMAT_BITS(pFormatFB)) | PM_TEXDATAFORMAT_FORMATEXTENSION(SURFFORMAT_FORMATEXTENSION_BITS(pFormatFB)) | PM_TEXDATAFORMAT_COLORORDER(COLOR_MODE)); SEND_P3_DATA(TextureMapFormat, ((PACKED_PP_LOOKUP(DDSurf_GetPixelPitch(pFBLcl)))) | (DDSurf_GetChipPixelSize(pFBLcl) << PM_TEXMAPFORMAT_TEXELSIZE) ); SEND_P3_DATA(ChromaLowerBound, LowerBound); SEND_P3_DATA(ChromaUpperBound, UpperBound); /* * Render the rectangle */ // set offset of source SEND_P3_DATA(SStart, rFB.left << 20); SEND_P3_DATA(TStart, rFB.top << 20); SEND_P3_DATA(dSdx, 1 << 20); SEND_P3_DATA(dSdyDom, 0); SEND_P3_DATA(dTdx, 0); SEND_P3_DATA(dTdyDom, 1 << 20); // set destination SEND_P3_DATA(StartXDom, rFB.left << 16); SEND_P3_DATA(StartXSub, rFB.right << 16); SEND_P3_DATA(StartY, rFB.top << 16); SEND_P3_DATA(dY, 1 << 16); SEND_P3_DATA(Count, rFB.bottom - rFB.top); SEND_P3_DATA(Render, __RENDER_TRAPEZOID_PRIMITIVE | __RENDER_TEXTURED_PRIMITIVE); // if (DDSurf_GetChipPixelSize(pSrcLcl) != __GLINT_8BITPIXEL) // { SEND_P3_DATA(DitherMode, 0); // } // Turn off chroma key and all the other unusual features SEND_P3_DATA(YUVMode, 0x0); SEND_P3_DATA(ColorDDAMode, 0x0); SEND_P3_DATA(TextureAddressMode, __PERMEDIA_DISABLE); SEND_P3_DATA(TextureColorMode, __PERMEDIA_DISABLE); SEND_P3_DATA(TextureReadMode, __PERMEDIA_DISABLE); P3_DMA_COMMIT_BUFFER(); #ifdef WANT_DMA if (pThisDisplay->pGLInfo->InterfaceType == GLINT_DMA) { // If we have queued up a DMA, we must send it now. P3_DMA_DEFS(); P3_DMA_GET_BUFFER(); if( (DWORD)dmaPtr != pThisDisplay->pGLInfo->DMAPartition[pThisDisplay->pGLInfo->CurrentPartition].VirtAddr ) { // Flush DMA buffer P3_DMA_FLUSH_BUFFER(); } } #endif START_SOFTWARE_CURSOR(pThisDisplay); return; } #endif // W95_DDRAW_VIDEO //@@END_DDKSPLIT //@@BEGIN_DDKSPLIT void PermediaBltYUVRGB( P3_THUNKEDDATA* pThisDisplay, LPDDRAWI_DDRAWSURFACE_LCL pSource, LPDDRAWI_DDRAWSURFACE_LCL pDest, P3_SURF_FORMAT* pFormatSource, P3_SURF_FORMAT* pFormatDest, DDBLTFX* lpBltFX, RECTL *rSrc, RECTL *rDest, DWORD windowBase, DWORD SourceOffset) { DWORD xScale; DWORD yScale; DWORD DestWidth = rDest->right - rDest->left; DWORD DestHeight = rDest->bottom - rDest->top; DWORD SourceWidth = rSrc->right - rSrc->left; DWORD SourceHeight = rSrc->bottom - rSrc->top; P3_DMA_DEFS(); ASSERTDD(pDest, "Not valid surface in destination"); ASSERTDD(pSource, "Not valid surface in source"); xScale = (SourceWidth << 20) / DestWidth; yScale = (SourceHeight << 20) / DestHeight; P3_DMA_GET_BUFFER(); P3_ENSURE_DX_SPACE(50); WAIT_FIFO(17); SEND_P3_DATA(FBReadPixel, DDSurf_GetChipPixelSize(pDest)); if (DDSurf_GetChipPixelSize(pSource) != __GLINT_8BITPIXEL) { SEND_P3_DATA(DitherMode, (COLOR_MODE << PM_DITHERMODE_COLORORDER) | (SURFFORMAT_FORMAT_BITS(pFormatDest) << PM_DITHERMODE_COLORFORMAT) | (SURFFORMAT_FORMATEXTENSION_BITS(pFormatDest) << PM_DITHERMODE_COLORFORMATEXTENSION) | (1 << PM_DITHERMODE_ENABLE) | (1 << PM_DITHERMODE_DITHERENABLE)); } SEND_P3_DATA(FBWindowBase, windowBase); // set no read of source. SEND_P3_DATA(FBReadMode, PACKED_PP_LOOKUP(DDSurf_GetPixelPitch(pDest))); SEND_P3_DATA(LogicalOpMode, __PERMEDIA_DISABLE); // set base of source SEND_P3_DATA(TextureBaseAddress, SourceOffset); SEND_P3_DATA(TextureAddressMode, PM_TEXADDRESSMODE_ENABLE(__PERMEDIA_ENABLE)); SEND_P3_DATA(TextureColorMode, PM_TEXCOLORMODE_ENABLE(__PERMEDIA_ENABLE) | PM_TEXCOLORMODE_APPLICATIONMODE(__GLINT_TEXCOLORMODE_APPLICATION_COPY)); SEND_P3_DATA(TextureReadMode, PM_TEXREADMODE_ENABLE(__PERMEDIA_ENABLE) | PM_TEXREADMODE_FILTER(__PERMEDIA_DISABLE) | PM_TEXREADMODE_WIDTH(11) | PM_TEXREADMODE_HEIGHT(11) ); SEND_P3_DATA(TextureDataFormat, PM_TEXDATAFORMAT_FORMAT(SURFFORMAT_FORMAT_BITS(pFormatSource)) | PM_TEXDATAFORMAT_FORMATEXTENSION(SURFFORMAT_FORMATEXTENSION_BITS(pFormatSource)) | PM_TEXDATAFORMAT_COLORORDER(INV_COLOR_MODE)); SEND_P3_DATA(TextureMapFormat, PACKED_PP_LOOKUP(DDSurf_GetPixelPitch(pSource)) | (DDSurf_GetChipPixelSize(pSource) << PM_TEXMAPFORMAT_TEXELSIZE) ); // Turn on the YUV unit SEND_P3_DATA(YUVMode, 0x1); SEND_P3_DATA(LogicalOpMode, 0); // set offset of source SEND_P3_DATA(SStart, rSrc->left << 20); SEND_P3_DATA(TStart, (rSrc->top<< 20)); SEND_P3_DATA(dSdx, xScale); SEND_P3_DATA(dSdyDom, 0); WAIT_FIFO(14); SEND_P3_DATA(dTdx, 0); SEND_P3_DATA(dTdyDom, yScale); /* * Render the rectangle */ SEND_P3_DATA(StartXDom, rDest->left << 16); SEND_P3_DATA(StartXSub, rDest->right << 16); SEND_P3_DATA(StartY, rDest->top << 16); SEND_P3_DATA(dY, 1 << 16); SEND_P3_DATA(Count, rDest->bottom - rDest->top); SEND_P3_DATA(Render, __RENDER_TRAPEZOID_PRIMITIVE | __RENDER_TEXTURED_PRIMITIVE); if (DDSurf_GetChipPixelSize(pSource) != __GLINT_8BITPIXEL) { SEND_P3_DATA(DitherMode, 0); } // Turn off the YUV unit SEND_P3_DATA(YUVMode, 0x0); SEND_P3_DATA(TextureAddressMode, PM_TEXADDRESSMODE_ENABLE(__PERMEDIA_DISABLE)); SEND_P3_DATA(TextureColorMode, PM_TEXCOLORMODE_ENABLE(__PERMEDIA_DISABLE)); SEND_P3_DATA(TextureReadMode, __PERMEDIA_DISABLE); P3_DMA_COMMIT_BUFFER(); } //@@END_DDKSPLIT