|
|
/******************************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 <mmsystem.h>
#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 <dvp.h>
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
|