Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3763 lines
142 KiB

/******************************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