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