|
|
/******************************Module*Header**********************************\
* * ************************** * * DirectDraw SAMPLE CODE * * ************************** * * Module Name: ddover.c * * Content: DirectDraw Overlays implementation * * Copyright (c) 1994-1999 3Dlabs Inc. Ltd. All rights reserved. * Copyright (c) 1995-2003 Microsoft Corporation. All rights reserved. \*****************************************************************************/
#include "glint.h"
#include "dma.h"
#include "ddover.h"
#define P3R3DX_VIDEO 1
#include "ramdac.h"
#if WNT_DDRAW
#define ENABLE_OVERLAY(pThisDisplay, flag) \
FORCED_IN_ORDER_WRITE ( pThisDisplay->bOverlayEnabled, flag )
#define SET_OVERLAY_HEIGHT(pThisDisplay, height) \
FORCED_IN_ORDER_WRITE ( pThisDisplay->VBLANKUpdateOverlayHeight, height ) #define SET_OVERLAY_WIDTH(pThisDisplay, width) \
FORCED_IN_ORDER_WRITE ( pThisDisplay->VBLANKUpdateOverlayWidth, width ) #else
#define ENABLE_OVERLAY(pThisDisplay, flag) \
FORCED_IN_ORDER_WRITE ( pThisDisplay->pGLInfo->bOverlayEnabled, flag )
#define SET_OVERLAY_HEIGHT(pThisDisplay, height) \
FORCED_IN_ORDER_WRITE ( pThisDisplay->pGLInfo->VBLANKUpdateOverlayHeight, height ) #define SET_OVERLAY_WIDTH(pThisDisplay, width) \
FORCED_IN_ORDER_WRITE ( pThisDisplay->pGLInfo->VBLANKUpdateOverlayWidth, width ) #endif // WNT_DDRAW
// Flags used in the dwOverlayFiltering entry.
#define OVERLAY_FILTERING_X 0x1
#define OVERLAY_FILTERING_Y 0x2
// The table that says whether the overlay will actually work at
// This res, dot clock, etc.
typedef struct OverlayWorksEntry_tag { int iMemBandwidth; // Actually just memory clock in kHz (well, 1024Hz units actually).
int iDotBandwidth; // In kbytes/sec, i.e. dotclock * pixel depth / 2^10
int iSourceWidth; // In bytes, i.e. pixels*depth.
int iWidthCoverage; // Fraction of screen covered by overlay horizontally * 0x10000
} OverlayWorksEntry;
// This table lists areas that the overlay works in. If there is more memory
// bandwidth, and less of the other factors than given on any single line,
// then the overlay will work. If no single line covers the current mode,
// then the overlay will fail.
// Having more memory bandwidth is fine, and having less for all the others
// is fine - the overlay will still work.
#define SIZE_OF_OVERLAY_WORKS_TABLE 18
// DVD size is 1440 wide (720 YUYV pixels).
static OverlayWorksEntry OverlayWorksTable[SIZE_OF_OVERLAY_WORKS_TABLE] = { { 68359, 210937, 928, 0x10000 }, // Max source width at 70MHz, 1152x864x16,75Hz
{ 68359, 210937, 1024, 0x06000 }, // Max coverage of 1024 width at 70MHz, 1152x864x16,75Hz
{ 68359, 210937, 2048, 0x04000 }, // Max coverage of 2048 width at 70MHz, 1152x864x16,75Hz
{ 68359, 421875, 864, 0x10000 }, // Max source width at 70MHz, 1152x864x32,75Hz
{ 68359, 421875, 1024, 0x04400 }, // Max coverage of 1024 width at 70MHz, 1152x864x32,75Hz
{ 68359, 421875, 2048, 0x03800 }, // Max coverage of 2048 width at 70MHz, 1152x864x32,75Hz
{ 87890, 210937, 1440, 0x10000 }, // Max source width at 90MHz, 1152x864x16,75Hz
{ 87890, 210937, 2048, 0x07000 }, // Max coverage of 2048 width at 90MHz, 1152x864x16,75Hz
{ 87890, 421875, 1152, 0x10000 }, // Max source width at 90MHz, 1152x864x32,75Hz
{ 87890, 421875, 1440, 0x09000 }, // Max DVD size at 90MHz, 1152x864x32,75Hz
{ 87890, 421875, 2048, 0x05500 }, // Max coverage of 2048 width at 90MHz, 1152x864x32,75Hz
{ 87890, 685546, 834, 0x10000 }, // Max source width at 90MHz, 1600x1200x32,64Hz
{ 87890, 685546, 2048, 0x03000 }, // Max coverage of 2048 width at 90MHz, 1600x1200x32,64Hz
// Shipping clock is 110, so measure at 105 just to be on the safe side.
{ 102559, 210937, 2048, 0x07155 }, // Max coverage of 2048 width at 105MHz, 1152x864x16,75Hz
{ 102559, 306640, 1440, 0x10000 }, // Max resoloution for fulscreen DVD at 105MHz: 1024x768x32,75Hz
{ 102559, 421875, 1440, 0x09e38 }, // Max DVD size at 105MHz, 1152x864x32,75Hz
{ 102559, 421875, 2048, 0x0551c }, // Max coverage of 2048 width at 105MHz, 1152x864x32,75Hz
// ...and one that only just works at 109MHz!
{ 106445, 421875, 1440, 0x10000 } // Max DVD size at 109MHz, 1152x864x32,75Hz
};
//-----------------------------------------------------------------------------
//
// __OV_Compute_Best_Fit_Delta
//
// Function to calculate a 12.12 delta value to provide scaling from
// a src_dimension to the target dest_dimension.
// The dest_dimension is not adjustable, but the src_dimension may be adjusted
// slightly, so that the delta yields a more accurate value for dest.
// filter_adj should be set to 1 if linear filtering is going to be anabled
// during scaling, and 0 otherwise.
// int_bits indicates the number of bits in the scaled delta format
//
//-----------------------------------------------------------------------------
int __OV_Compute_Best_Fit_Delta( unsigned long *src_dimension, unsigned long dest_dimension, unsigned long filter_adj, unsigned long int_bits, unsigned long *best_delta) { int result = 0; float fp_delta; float delta; unsigned long delta_mid; unsigned long delta_down; unsigned long delta_up; float mid_src_dim; float down_src_dim; float up_src_dim; float mid_err; float mid_frac; int mid_ok; float down_err; float down_frac; int down_ok; float up_err; float up_frac; int up_ok; int itemp;
// The value at which a scaled delta value is deemed too large
const unsigned int max_scaled_int = (1 << (12+int_bits));
// Calculate an exact floating point delta
fp_delta = (float)(*src_dimension - filter_adj) / dest_dimension;
// Calculate the scaled representation of the delta
delta = (fp_delta * (1<<12));
// Truncate to max_int
if (delta >= max_scaled_int) { delta = (float)(max_scaled_int - 1); // Just below the overflow value
}
// Calculate the scaled approximation to the delta
myFtoi(&delta_mid, delta);
// Calculate the scaled approximation to the delta, less a 'bit'
// But don't let it go out of range
myFtoi(&delta_down, delta); if (delta_down != 0) { delta_down --; }
// Calculate the scaled approximation to the delta, plus a 'bit'
// But don't let it go out of range
myFtoi(&delta_up, delta); if ((delta_up + 1) < max_scaled_int) { delta_up ++; }
// Recompute the source dimensions, based on the dest and deltas
mid_src_dim = (((float)(dest_dimension - 1) * delta_mid) / (1<<12)) + filter_adj;
down_src_dim = (((float)(dest_dimension - 1) * delta_down) / (1<<12)) + filter_adj;
up_src_dim = (((float)(dest_dimension - 1) * delta_up) / (1<<12)) + filter_adj;
// Choose the delta which gives final source coordinate closest the target,
// while giving a fraction 'f' such that (1.0 - f) <= delta
mid_err = (float)myFabs(mid_src_dim - *src_dimension); myFtoi(&itemp, mid_src_dim); mid_frac = mid_src_dim - itemp; mid_ok = ((1.0 - mid_frac) <= ((float)(delta_mid) / (1<<12)));
down_err = (float)myFabs(down_src_dim - *src_dimension); myFtoi(&itemp, down_src_dim); down_frac = down_src_dim - itemp; down_ok = ((1.0 - down_frac) <= ((float)(delta_down) / (1<<12)));
up_err = (float)myFabs(up_src_dim - *src_dimension); myFtoi(&itemp, up_src_dim); up_frac = (up_src_dim - itemp); up_ok = ((1.0 - up_frac) <= ((float)(delta_up) / (1<<12)));
if (mid_ok && (!down_ok || (mid_err <= down_err)) && (!up_ok || (mid_err <= up_err))) { *best_delta = delta_mid; myFtoi(&itemp, (mid_src_dim + ((float)(delta_mid) / (1<<12)))); *src_dimension = (unsigned long)(itemp - filter_adj);
result = 1; } else if (down_ok && (!mid_ok || (down_err <= mid_err)) && (!up_ok || (down_err <= up_err )) ) { *best_delta = delta_down; myFtoi(&itemp, (down_src_dim + ((float)(delta_down) / (1<<12)))); *src_dimension = (unsigned long)(itemp - filter_adj);
result = 1; } else if (up_ok && (!mid_ok || (up_err <= mid_err )) && (!down_ok || (up_err <= down_err)) ) { *best_delta = delta_up; myFtoi(&itemp, (up_src_dim + ((float)(delta_up) / (1<<12)))); *src_dimension = (unsigned long)(itemp - filter_adj); result = 1; } else { result = 0; *best_delta = delta_mid; myFtoi(&itemp, (mid_src_dim + ((float)(delta_mid) / (1<<12)))); myFtoi(&itemp, (itemp - filter_adj) + 0.9999f); *src_dimension = (unsigned long)itemp; }
return result; } // __OV_Compute_Best_Fit_Delta
//-----------------------------------------------------------------------------
//
// __OV_Find_Zoom
//
//-----------------------------------------------------------------------------
#define VALID_WIDTH(w) ((w & 3) == 0)
#define MAKE_VALID_WIDTH(w) ((w) & ~0x3)
#define WIDTH_STEP 4
int __OV_Find_Zoom( unsigned long src_width, unsigned long* shrink_width, unsigned long dest_width, unsigned long* zoom_delta, BOOL bFilter) { int zoom_ok; int zx_adj = 0;
// Find a suitable zoom delta for the given source
// the source image may be adjusted in width by as much as 8 pixels to
// acheive a match
// Find zoom for requested width
unsigned long trunc_width = MAKE_VALID_WIDTH(*shrink_width); zoom_ok = __OV_Compute_Best_Fit_Delta(&trunc_width, dest_width, zx_adj, (bFilter ? 1 : 0), zoom_delta);
// If no zoom was matched for the requested width, start searching up and down
if (!zoom_ok || (!VALID_WIDTH(trunc_width))) { unsigned long up_width = MAKE_VALID_WIDTH(trunc_width) + WIDTH_STEP; unsigned long down_width = MAKE_VALID_WIDTH(trunc_width) - WIDTH_STEP;
int done_up = 0; int done_down = 0; do { // Check upwards
zoom_ok = 0; if (up_width < dest_width) { unsigned long new_width = up_width; zoom_ok = __OV_Compute_Best_Fit_Delta(&new_width, dest_width, zx_adj, (bFilter ? 1 : 0), zoom_delta);
// If the above call somehow adjusts width to invalid,
// mark the delta invalid
if (!VALID_WIDTH(new_width)) { zoom_ok = 0; }
if (zoom_ok) { *shrink_width = new_width; } else { up_width += WIDTH_STEP; } } else done_up = 1;
// Check downwards
if (!zoom_ok && (down_width >= 4) && (down_width < src_width)) { unsigned long new_width = down_width; zoom_ok = __OV_Compute_Best_Fit_Delta(&new_width, dest_width, zx_adj, (bFilter ? 1 : 0), zoom_delta);
// If the above call somehow adjusts width to invalid,
// mark the delta invalid
if (!VALID_WIDTH(new_width)) { zoom_ok = 0; }
if (zoom_ok) { *shrink_width = new_width; } else { down_width -= WIDTH_STEP; } } else { done_down = 1; } } while (!zoom_ok && (!done_up || !done_down)); } return zoom_ok; } // __OV_Find_Zoom
//-----------------------------------------------------------------------------
//
// __OV_Compute_Params
//
//-----------------------------------------------------------------------------
unsigned long __OV_Compute_Params( unsigned long src_width, unsigned long dest_width, unsigned long *ovr_shrinkxd, unsigned long *ovr_zoomxd, unsigned long *ovr_w, BOOL bFilter) { unsigned long iterations = 0;
unsigned long sx_adj = 0;
const unsigned long fixed_one = 0x00001000;
//
// Use the source and destination rectangle dimensions to compute
// delta values
//
int zoom_ok;
unsigned long adj_src_width = src_width + 1; // +1 to account for -- below
unsigned long exact_shrink_xd; unsigned long exact_zoom_xd;
do { unsigned long shrink_width;
// Step to next source width
adj_src_width--;
// Make a stab at the deltas for the current source width
// Initially, the deltas are assumed to be 1, and the width due to
// shrinking is therefore equal to src width
shrink_width = adj_src_width; exact_shrink_xd = fixed_one; exact_zoom_xd = fixed_one;
// Compute the shrink width and delta required
if (dest_width < adj_src_width) { // Shrink
myFtoi(&exact_shrink_xd, (((float)(adj_src_width - sx_adj) / (float)(dest_width)) * (1<<12)) + 0.999f);
myFtoi(&shrink_width,(adj_src_width - sx_adj) / ((float)(exact_shrink_xd) / (1<<12)));
}
// Truncate shrink to valid width
if (!VALID_WIDTH(shrink_width) && (shrink_width > 4)) { shrink_width = MAKE_VALID_WIDTH(shrink_width); myFtoi(&exact_shrink_xd,(((float)(adj_src_width - sx_adj) / (float)(shrink_width)) * (1<<12)) + 0.999f); }
// Compute any zoom delta required
zoom_ok = 1; if (shrink_width < dest_width) { // Make an attempt at a zoom delta, and shrink-width for this src width
zoom_ok = __OV_Find_Zoom(adj_src_width, &shrink_width, dest_width, &exact_zoom_xd, bFilter);
// Compute shrink delta
myFtoi(&exact_shrink_xd,(((float)(adj_src_width - sx_adj) / (float)(shrink_width)) * (1<<12)) + 0.999f); } } while (0);
*ovr_zoomxd = exact_zoom_xd; *ovr_shrinkxd = exact_shrink_xd; *ovr_w = adj_src_width;
return iterations; } // __OV_Compute_Params
//-----------------------------------------------------------------------------
//
// __OV_ClipRectangles
//
// Clip the dest rectangle against the screen and change the source
// rect appropriately
//
//-----------------------------------------------------------------------------
void __OV_ClipRectangles( P3_THUNKEDDATA* pThisDisplay, DRVRECT* rcNewSrc, DRVRECT* rcNewDest) { float ScaleX; float ScaleY; float OffsetX; float OffsetY; float fTemp; DRVRECT rcSrc; DRVRECT rcDest;
// Find the scale and offset from screen rects to overlay rects.
// This is like a transform to take the dest rect to the source.
ScaleX = (float)( pThisDisplay->P3Overlay.rcSrc.right - pThisDisplay->P3Overlay.rcSrc.left ) / (float)( pThisDisplay->P3Overlay.rcDest.right - pThisDisplay->P3Overlay.rcDest.left ); ScaleY = (float)(pThisDisplay->P3Overlay.rcSrc.bottom - pThisDisplay->P3Overlay.rcSrc.top ) / (float)( pThisDisplay->P3Overlay.rcDest.bottom - pThisDisplay->P3Overlay.rcDest.top ); OffsetX = ((float)pThisDisplay->P3Overlay.rcSrc.left / ScaleX) - (float)pThisDisplay->P3Overlay.rcDest.left; OffsetY = ((float)pThisDisplay->P3Overlay.rcSrc.top / ScaleY) - (float)pThisDisplay->P3Overlay.rcDest.top;
// Clip the dest against the screen
if (pThisDisplay->P3Overlay.rcDest.right > (LONG)pThisDisplay->dwScreenWidth) { rcDest.right = (LONG)pThisDisplay->dwScreenWidth; } else { rcDest.right = pThisDisplay->P3Overlay.rcDest.right; }
if (pThisDisplay->P3Overlay.rcDest.left < 0) { rcDest.left = 0; } else { rcDest.left = pThisDisplay->P3Overlay.rcDest.left; }
if (pThisDisplay->P3Overlay.rcDest.top < 0) { rcDest.top = 0; } else { rcDest.top = pThisDisplay->P3Overlay.rcDest.top; }
if (pThisDisplay->P3Overlay.rcDest.bottom > (LONG)pThisDisplay->dwScreenHeight) { rcDest.bottom = (LONG)pThisDisplay->dwScreenHeight; } else { rcDest.bottom = pThisDisplay->P3Overlay.rcDest.bottom; }
// Transform the new dest rect to the new source rect
fTemp = ( ( (float)rcDest.left + OffsetX ) * ScaleX + 0.499f); myFtoi ( (int*)&(rcSrc.left), fTemp );
fTemp = ( ( (float)rcDest.right + OffsetX ) * ScaleX + 0.499f); myFtoi ( (int*)&(rcSrc.right), fTemp );
fTemp = ( ( (float)rcDest.top + OffsetY ) * ScaleY + 0.499f); myFtoi ( (int*)&(rcSrc.top), fTemp );
fTemp = ( ( (float)rcDest.bottom + OffsetY ) * ScaleY + 0.499f); myFtoi ( (int*)&(rcSrc.bottom), fTemp );
*rcNewSrc = rcSrc; *rcNewDest = rcDest;
DISPDBG((DBGLVL,"rcSrc.left: %d, rcSrc.right: %d", rcSrc.left, rcSrc.right)); DISPDBG((DBGLVL,"rcDest.left: %d, rcDest.right: %d", rcDest.left, rcDest.right)); return; } // __OV_ClipRectangles
//-----------------------------------------------------------------------------
//
// _DD_OV_UpdateSource
//
// Update the source DDRAW surface that we are displaying from
// This routine is also used when using the overlay to stretch up for a
// DFP display, so the DDraw overlay mechnism may be disabled and inactive
// when this is called. It must allow for this.
//
//-----------------------------------------------------------------------------
void _DD_OV_UpdateSource( P3_THUNKEDDATA* pThisDisplay, LPDDRAWI_DDRAWSURFACE_LCL pSurf) { DWORD dwOverlaySourceOffset;
DISPDBG ((DBGLVL,"** In _DD_OV_UpdateSource"));
// Update current overlay surface
pThisDisplay->P3Overlay.pCurrentOverlay = pSurf->lpGbl->fpVidMem;
// Increase the buffer index
pThisDisplay->P3Overlay.dwCurrentVideoBuffer++; if (pThisDisplay->P3Overlay.dwCurrentVideoBuffer > 2) { pThisDisplay->P3Overlay.dwCurrentVideoBuffer = 0; }
dwOverlaySourceOffset = (DWORD)(pSurf->lpGbl->fpVidMem - pThisDisplay->dwScreenFlatAddr); switch (DDSurf_BitDepth(pSurf)) { case 8: break; case 16: dwOverlaySourceOffset >>= 1; break; case 32: dwOverlaySourceOffset >>= 2; break; default: DISPDBG((ERRLVL,"Oops Overlay depth makes no sense")); break; }
switch(pThisDisplay->P3Overlay.dwCurrentVideoBuffer) { case 0: LOAD_GLINT_CTRL_REG(VideoOverlayBase0, dwOverlaySourceOffset); LOAD_GLINT_CTRL_REG(VideoOverlayIndex, 0); break; case 1: LOAD_GLINT_CTRL_REG(VideoOverlayBase1, dwOverlaySourceOffset); LOAD_GLINT_CTRL_REG(VideoOverlayIndex, 1); break; case 2: LOAD_GLINT_CTRL_REG(VideoOverlayBase2, dwOverlaySourceOffset); LOAD_GLINT_CTRL_REG(VideoOverlayIndex, 2); break; }
} // _DD_OV_UpdateSource
//-----------------------------------------------------------------------------
//
// __OV_UpdatePosition
//
// Given the correct starting rectangle, this function clips it against the
// screen and updates the overlay position registers.
// If *pdwShrinkFactor is NULL, then the overlay is updated, otherwise the
// desired shrink factor is put in *pdwShrinkFactor and the registers are
// NOT updated. This is so the shrink factor can be checked to see if the
// overlay would actually work in this case.
//
//-----------------------------------------------------------------------------
void __OV_UpdatePosition( P3_THUNKEDDATA* pThisDisplay, DWORD *pdwShrinkFactor) { DWORD dwSrcWidth; DWORD dwSrcHeight; DWORD dwDestHeight; DWORD dwDestWidth; DWORD dwXDeltaZoom; DWORD dwXDeltaShrink; DWORD dwYDelta; DWORD dwSrcAdjust; DRVRECT rcNewSrc; DRVRECT rcNewDest; P3RDRAMDAC *pP3RDRegs; DWORD dwLastShrink; DWORD dwLastZoom; DISPDBG ((DBGLVL,"**In __OV_UpdatePosition"));
// Get a pointer to the ramdac
pP3RDRegs = (P3RDRAMDAC *)&(pThisDisplay->pGlint->ExtVCReg);
// Get the clipped destination rectangles
__OV_ClipRectangles(pThisDisplay, &rcNewSrc, &rcNewDest);
// Get the widths
dwDestWidth = (DWORD)(rcNewDest.right - rcNewDest.left); dwDestHeight = (DWORD)(rcNewDest.bottom - rcNewDest.top); dwSrcWidth = (DWORD)(rcNewSrc.right - rcNewSrc.left); dwSrcHeight = (DWORD)(rcNewSrc.bottom - rcNewSrc.top);
if ( pThisDisplay->bOverlayPixelDouble ) { // We need to double the destination width first.
dwDestWidth <<= 1; }
// Compute the overlay parameters
__OV_Compute_Params(dwSrcWidth, dwDestWidth, &dwXDeltaShrink, &dwXDeltaZoom, &dwSrcAdjust, ( ( pThisDisplay->dwOverlayFiltering & OVERLAY_FILTERING_X ) != 0 ) ); DISPDBG((DBGLVL,"OVERLAY: XShrink 0x%x", dwXDeltaShrink)); DISPDBG((DBGLVL,"OVERLAY: XZoom 0x%x", dwXDeltaZoom));
if ( pdwShrinkFactor != NULL ) { // We just wanted to know the shrink factor.
*pdwShrinkFactor = dwXDeltaShrink; return; }
dwLastZoom = READ_GLINT_CTRL_REG(VideoOverlayZoomXDelta); dwLastShrink = READ_GLINT_CTRL_REG(VideoOverlayShrinkXDelta);
if ( ((dwLastZoom >> 4) != dwXDeltaZoom) || ((dwLastShrink >> 4) != dwXDeltaShrink) ) { //dwCurrentMode = READ_GLINT_CTRL_REG(VideoOverlayMode);
//LOAD_GLINT_CTRL_REG(VideoOverlayMode, 0);
LOAD_GLINT_CTRL_REG(VideoOverlayZoomXDelta, (dwXDeltaZoom << 4)); LOAD_GLINT_CTRL_REG(VideoOverlayShrinkXDelta, (dwXDeltaShrink << 4)); DISPDBG((DBGLVL,"OVERLAY: VideoOverlayZoomXDelta 0x%x", dwXDeltaZoom << 4)); DISPDBG((DBGLVL,"OVERLAY: VideoOverlayShrinkXDelta 0x%x", dwXDeltaShrink << 4));
//LOAD_GLINT_CTRL_REG(VideoOverlayMode, dwCurrentMode);
}
// Load up the Y scaling
if ( ( pThisDisplay->dwOverlayFiltering & OVERLAY_FILTERING_Y ) != 0 ) { // Apply filtering.
dwYDelta = ( ( ( dwSrcHeight - 1 ) << 12 ) + dwDestHeight - 1 ) / dwDestHeight; // Make sure this will cause proper termination
ASSERTDD ( ( dwYDelta * dwDestHeight ) >= ( ( dwSrcHeight - 1 ) << 12 ), "** __OV_UpdatePosition: dwYDelta is not big enough" ); ASSERTDD ( ( dwYDelta * ( dwDestHeight - 1 ) ) < ( ( dwSrcHeight - 1 ) << 12 ), "** __OV_UpdatePosition: dwYDelta is too big" ); dwYDelta <<= 4; } else { dwYDelta = ( ( dwSrcHeight << 12 ) + dwDestHeight - 1 ) / dwDestHeight; // Make sure this will cause proper termination
ASSERTDD ( ( dwYDelta * dwDestHeight ) >= ( dwSrcHeight << 12 ), "** __OV_UpdatePosition: dwYDelta is not big enough" ); ASSERTDD ( ( dwYDelta * ( dwDestHeight - 1 ) ) < ( dwSrcHeight << 12 ), "** __OV_UpdatePosition: dwYDelta is too big" ); dwYDelta <<= 4; } LOAD_GLINT_CTRL_REG(VideoOverlayYDelta, dwYDelta);
// Width & Height
if ( RENDERCHIP_PERMEDIAP3 ) { // These registers are _not_ synched to VBLANK like all the others,
// so we need to do it manually.
if ( ( pThisDisplay->dwOverlayFiltering & OVERLAY_FILTERING_Y ) != 0 ) { SET_OVERLAY_HEIGHT ( pThisDisplay, ( rcNewSrc.bottom - rcNewSrc.top - 1 ) ); } else { SET_OVERLAY_HEIGHT ( pThisDisplay, rcNewSrc.bottom - rcNewSrc.top ); } SET_OVERLAY_WIDTH ( pThisDisplay, rcNewSrc.right - rcNewSrc.left ); } else { // These auto-sync on everything else.
LOAD_GLINT_CTRL_REG(VideoOverlayWidth, rcNewSrc.right - rcNewSrc.left); LOAD_GLINT_CTRL_REG(VideoOverlayHeight, rcNewSrc.bottom - rcNewSrc.top); }
// Origin of source
LOAD_GLINT_CTRL_REG(VideoOverlayOrigin, (rcNewSrc.top << 16) | (rcNewSrc.left & 0xFFFF));
DISPDBG((DBGLVL,"OVERLAY: VideoOverlayWidth 0x%x", rcNewSrc.right - rcNewSrc.left)); DISPDBG((DBGLVL,"OVERLAY: VideoOverlayHeight 0x%x", rcNewSrc.bottom - rcNewSrc.top)); DISPDBG((DBGLVL,"OVERLAY: VideoOverlayOrigin 0x%x", (rcNewSrc.top << 16) | (rcNewSrc.left & 0xFFFF) )); DISPDBG((DBGLVL,"OVERLAY: VideoOverlayYDelta 0x%x", dwYDelta ));
// Setup Overlay Dest in RAMDAC Unit.
// RAMDAC registers are only 8bits wide.
if ( pThisDisplay->bOverlayPixelDouble ) { // Need to double all these numbers.
P3RD_LOAD_INDEX_REG(P3RD_VIDEO_OVERLAY_XSTARTLOW, ((rcNewDest.left << 1) & 0xFF)); P3RD_LOAD_INDEX_REG(P3RD_VIDEO_OVERLAY_XSTARTHIGH, (rcNewDest.left >> 7));
P3RD_LOAD_INDEX_REG(P3RD_VIDEO_OVERLAY_XENDLOW, ((rcNewDest.right << 1 ) & 0xFF)); P3RD_LOAD_INDEX_REG(P3RD_VIDEO_OVERLAY_XENDHIGH, (rcNewDest.right >> 7)); } else { P3RD_LOAD_INDEX_REG(P3RD_VIDEO_OVERLAY_XSTARTLOW, (rcNewDest.left & 0xFF)); P3RD_LOAD_INDEX_REG(P3RD_VIDEO_OVERLAY_XSTARTHIGH, (rcNewDest.left >> 8));
P3RD_LOAD_INDEX_REG(P3RD_VIDEO_OVERLAY_XENDLOW, (rcNewDest.right & 0xFF)); P3RD_LOAD_INDEX_REG(P3RD_VIDEO_OVERLAY_XENDHIGH, (rcNewDest.right >> 8)); }
P3RD_LOAD_INDEX_REG(P3RD_VIDEO_OVERLAY_YSTARTLOW, (rcNewDest.top & 0xFF)); P3RD_LOAD_INDEX_REG(P3RD_VIDEO_OVERLAY_YSTARTHIGH, (rcNewDest.top >> 8)); P3RD_LOAD_INDEX_REG(P3RD_VIDEO_OVERLAY_YENDLOW, (rcNewDest.bottom & 0xFF)); P3RD_LOAD_INDEX_REG(P3RD_VIDEO_OVERLAY_YENDHIGH, (rcNewDest.bottom >> 8));
DISPDBG((DBGLVL,"OVERLAY: P3RD_VIDEO_OVERLAY_XSTARTLOW 0x%x", (rcNewDest.left & 0xFF) )); DISPDBG((DBGLVL,"OVERLAY: P3RD_VIDEO_OVERLAY_XSTARTHIGH 0x%x", (rcNewDest.left >> 8) )); DISPDBG((DBGLVL,"OVERLAY: P3RD_VIDEO_OVERLAY_YSTARTLOW 0x%x", (rcNewDest.top & 0xFF) )); DISPDBG((DBGLVL,"OVERLAY: P3RD_VIDEO_OVERLAY_YSTARTHIGH 0x%x", (rcNewDest.top >> 8) )); DISPDBG((DBGLVL,"OVERLAY: P3RD_VIDEO_OVERLAY_XENDLOW 0x%x", (rcNewDest.right & 0xFF) )); DISPDBG((DBGLVL,"OVERLAY: P3RD_VIDEO_OVERLAY_XENDHIGH 0x%x", (rcNewDest.right >> 8) )); DISPDBG((DBGLVL,"OVERLAY: P3RD_VIDEO_OVERLAY_YENDLOW 0x%x", (rcNewDest.bottom & 0xFF) )); DISPDBG((DBGLVL,"OVERLAY: P3RD_VIDEO_OVERLAY_YENDHIGH 0x%x", (rcNewDest.bottom >> 8) )); } // __OV_UpdatePosition
//-----------------------------------------------------------------------------
//
// DdUpdateOverlay
//
// Repositions or modifies the visual attributes of an overlay surface.
//
// DdUpdateOverlay shows, hides, or repositions an overlay surface on the
// screen. It also sets attributes of the overlay surface, such as the stretch
// factor or type of color key to be used.
//
// The driver should determine whether it has the bandwidth to support the
// overlay update request. The driver should use dwFlags to determine the type
// of request and how to process it.
//
// The driver/hardware must stretch or shrink the overlay accordingly when the
// rectangles specified by rDest and rSrc are different sizes.
//
// Note that DdFlip is used for flipping between overlay surfaces, so
// performance for DdUpdateOverlay is not critical.
//
//
// Parameters
//
// puod
// Points to a DD_UPDATEOVERLAYDATA structure that contains the
// information required to update the overlay.
//
// .lpDD
// Points to a DD_DIRECTDRAW_GLOBAL structure that represents
// the DirectDraw object.
// .lpDDDestSurface
// Points to a DD_SURFACE_LOCAL structure that represents the
// DirectDraw surface to be overlaid. This value can be NULL
// if DDOVER_HIDE is specified in dwFlags.
// .rDest
// Specifies a RECTL structure that contains the x, y, width,
// and height of the region on the destination surface to be
// overlaid.
// .lpDDSrcSurface
// Points to a DD_SURFACE_LOCAL structure that describes the
// overlay surface.
// .rSrc
// Specifies a RECTL structure that contains the x, y, width,
// and height of the region on the source surface to be used
// for the overlay.
// .dwFlags
// Specifies how the driver should handle the overlay. This
// member can be a combination of any of the following flags:
//
// DDOVER_HIDE
// The driver should hide the overlay; that is, the driver
// should turn this overlay off.
// DDOVER_SHOW
// The driver should show the overlay; that is, the driver
// should turn this overlay on.
// DDOVER_KEYDEST
// The driver should use the color key associated with the
// destination surface.
// DDOVER_KEYDESTOVERRIDE
// The driver should use the dckDestColorKey member of the
// DDOVERLAYFX structure as the destination color key
// instead of the color key associated with the destination
// surface.
// DDOVER_KEYSRC
// The driver should use the color key associated with the
// destination surface.
// DDOVER_KEYSRCOVERRIDE
// The driver should use the dckSrcColorKey member of the
// DDOVERLAYFX structure as the source color key instead of
// the color key associated with the destination surface.
// DDOVER_DDFX
// The driver should show the overlay surface using the
// attributes specified by overlayFX.
// DDOVER_ADDDIRTYRECT
// Should be ignored by the driver.
// DDOVER_REFRESHDIRTYRECTS
// Should be ignored by the driver.
// DDOVER_REFRESHALL
// Should be ignored by the driver.
// DDOVER_INTERLEAVED
// The overlay surface is composed of interleaved fields.
// Drivers that support VPE need only check this flag.
// DDOVER_AUTOFLIP
// The driver should autoflip the overlay whenever the
// hardware video port autoflips. Drivers that support VPE
// need only check this flag.
// DDOVER_BOB
// The driver should display each field of VPE object data
// individually without causing any jittery artifacts. This
// flag pertains to both VPE and decoders that want to do
// their own flipping in kernel mode using the kernel-mode
// video transport functionality.
// DDOVER_OVERRIDEBOBWEAVE
// Bob/weave decisions should not be overridden by other
// interfaces. If the overlay mixer sets this flag, DirectDraw
// will not allow a kernel-mode driver to use the kernel-mode
// video transport functionality to switch the hardware
// between bob and weave mode.
// DDOVER_BOBHARDWARE
// Indicates that bob will be performed by hardware rather
// than by software or emulation. Drivers that support VPE
// need only check this flag.
//
// .overlayFX
// Specifies a DDOVERLAYFX structure describing additional effects
// that the driver should use to update the overlay. The driver
// should use this structure only if one of DDOVER_DDFX,
// DDOVER_KEYDESTOVERRIDE, or DDOVER_KEYSRCOVERRIDE are set in
// dwFlags.
// .ddRVal
// Specifies the location in which the driver writes the return
// value of the DdUpdateOverlay callback. A return code of DD_OK
// indicates success.
// .UpdateOverlay
// This is unused on Windows 2000.
//
//-----------------------------------------------------------------------------
DWORD CALLBACK DdUpdateOverlay( LPDDHAL_UPDATEOVERLAYDATA puod) { P3_THUNKEDDATA* pThisDisplay; DWORD dwDestColourKey; DWORD dwSrcColourKey;
BOOL bSrcColorKey = FALSE; BOOL bDestColorKey = FALSE; P3_SURF_FORMAT* pFormatOverlaySrc; P3_SURF_FORMAT* pFormatOverlayDest; DWORD dwOverlayControl = 0; P3RDRAMDAC *pP3RDRegs; VideoOverlayModeReg OverlayMode; RDVideoOverlayControlReg RDOverlayControl; DWORD dwVideoOverlayUpdate; int iCurEntry, iCurDotBandwidth, iCurMemBandwidth, iCurSourceWidth, iCurWidthCoverage; BOOL bNoFilterInY;
GET_THUNKEDDATA(pThisDisplay, puod->lpDD);
// Get a pointer to the ramdac
pP3RDRegs = (P3RDRAMDAC *)&(pThisDisplay->pGlint->ExtVCReg); DISPDBG ((DBGLVL,"**In DdUpdateOverlay dwFlags = %x",puod->dwFlags));
ZeroMemory(&OverlayMode, sizeof(VideoOverlayModeReg)); ZeroMemory(&RDOverlayControl, sizeof(RDOverlayControl));
do { dwVideoOverlayUpdate = READ_GLINT_CTRL_REG(VideoOverlayUpdate); } while ((dwVideoOverlayUpdate & 0x1) != 0);
// Are we hiding the overlay?
if (puod->dwFlags & DDOVER_HIDE) { DISPDBG((DBGLVL,"** DdUpdateOverlay - hiding."));
// Hide the overlay.
if (pThisDisplay->P3Overlay.dwVisibleOverlays == 0) { // No overlay being shown.
DISPDBG((WRNLVL,"** DdUpdateOverlay - DDOVER_HIDE - already hidden.")); puod->ddRVal = DDERR_OUTOFCAPS; return DDHAL_DRIVER_HANDLED; } // Hide an overlay which is not shown
if (pThisDisplay->P3Overlay.pCurrentOverlay != puod->lpDDSrcSurface->lpGbl->fpVidMem) { // No overlay being shown.
DISPDBG((WRNLVL,"** DdUpdateOverlay - overlay not visible.")); puod->ddRVal = DD_OK; return DDHAL_DRIVER_HANDLED; }
OverlayMode.Enable = __PERMEDIA_DISABLE; RDOverlayControl.Enable = __PERMEDIA_DISABLE; ENABLE_OVERLAY(pThisDisplay, FALSE); pThisDisplay->P3Overlay.pCurrentOverlay = (FLATPTR)NULL; pThisDisplay->P3Overlay.dwVisibleOverlays = 0; } // Are we showing the overlay?
else if ((puod->dwFlags & DDOVER_SHOW) || (pThisDisplay->P3Overlay.dwVisibleOverlays != 0)) { if (pThisDisplay->P3Overlay.dwVisibleOverlays > 0) { // Compare the video memory pointer to decide whether this is the
// the current overlay surface
if (pThisDisplay->P3Overlay.pCurrentOverlay != puod->lpDDSrcSurface->lpGbl->fpVidMem) { // Overlay is already being displayed. Can't have a new one.
DISPDBG((WRNLVL,"** DdUpdateOverlay - DDOVER_SHOW - already being shown, and it's a new surface.")); puod->ddRVal = DDERR_OUTOFCAPS; return DDHAL_DRIVER_HANDLED; } }
if (((pThisDisplay->pGLInfo->dwFlags & GMVF_DFP_DISPLAY) != 0) && ((pThisDisplay->pGLInfo->dwScreenWidth != pThisDisplay->pGLInfo->dwVideoWidth) || (pThisDisplay->pGLInfo->dwScreenHeight != pThisDisplay->pGLInfo->dwVideoHeight))) { // Display driver is using the overlay on a DFP, so we can't use it.
DISPDBG((WRNLVL,"** DdUpdateOverlay - DDOVER_SHOW - overlay being used for desktop stretching on DFP.")); puod->ddRVal = DDERR_OUTOFCAPS; return DDHAL_DRIVER_HANDLED; }
// See if the screen is currently byte-doubled.
if ( ( ( READ_GLINT_CTRL_REG(MiscControl) ) & 0x80 ) == 0 ) { pThisDisplay->bOverlayPixelDouble = FALSE; } else { pThisDisplay->bOverlayPixelDouble = TRUE; }
// Set up Video Overlay Color Format.
pFormatOverlaySrc = _DD_SUR_GetSurfaceFormat( puod->lpDDSrcSurface); pFormatOverlayDest = _DD_SUR_GetSurfaceFormat( puod->lpDDDestSurface);
pThisDisplay->P3Overlay.dwCurrentVideoBuffer = 0;
OverlayMode.Enable = __PERMEDIA_ENABLE; RDOverlayControl.Enable = __PERMEDIA_ENABLE;
ENABLE_OVERLAY(pThisDisplay, TRUE); pThisDisplay->P3Overlay.dwVisibleOverlays = 1;
if (pFormatOverlaySrc->DeviceFormat == SURF_YUV422) { OverlayMode.YUV = VO_YUV_422; OverlayMode.ColorOrder = VO_COLOR_ORDER_BGR; } else if (pFormatOverlaySrc->DeviceFormat == SURF_YUV444) { OverlayMode.YUV = VO_YUV_444; OverlayMode.ColorOrder = VO_COLOR_ORDER_BGR; } else { OverlayMode.YUV = VO_YUV_RGB; OverlayMode.ColorOrder = VO_COLOR_ORDER_RGB; switch (pFormatOverlaySrc->DitherFormat) { case P3RX_DITHERMODE_COLORFORMAT_8888: OverlayMode.ColorFormat = VO_CF_RGB8888; break;
case P3RX_DITHERMODE_COLORFORMAT_4444: OverlayMode.ColorFormat = VO_CF_RGB4444; break;
case P3RX_DITHERMODE_COLORFORMAT_5551: OverlayMode.ColorFormat = VO_CF_RGB5551; break;
case P3RX_DITHERMODE_COLORFORMAT_565: OverlayMode.ColorFormat = VO_CF_RGB565; break;
case P3RX_DITHERMODE_COLORFORMAT_332: OverlayMode.ColorFormat = VO_CF_RGB332; break;
case P3RX_DITHERMODE_COLORFORMAT_CI: OverlayMode.ColorFormat = VO_CF_RGBCI8; break;
default: DISPDBG((ERRLVL,"** DdUpdateOverlay: Unknown overlay pixel type")); puod->ddRVal = DDERR_INVALIDSURFACETYPE; return DDHAL_DRIVER_HANDLED; break; } }
// Set up Video Overlay Pixel Size
switch (pFormatOverlaySrc->dwBitsPerPixel) { case 8: OverlayMode.PixelSize = VO_PIXEL_SIZE8; RDOverlayControl.DirectColor = __PERMEDIA_DISABLE; break;
case 16: OverlayMode.PixelSize = VO_PIXEL_SIZE16; RDOverlayControl.DirectColor = __PERMEDIA_ENABLE; break;
case 32: OverlayMode.PixelSize = VO_PIXEL_SIZE32; RDOverlayControl.DirectColor = __PERMEDIA_ENABLE; break;
default: break; }
// Keep the rectangles
pThisDisplay->P3Overlay.rcDest = *(DRVRECT*)&puod->rDest;
if ( pThisDisplay->P3Overlay.rcDest.left == 1 ) { // Don't use 2 - it will "reveal" the (purple) colourkey colour.
pThisDisplay->P3Overlay.rcDest.left = 0; } if ( pThisDisplay->P3Overlay.rcDest.right == 1 ) { // Don't use 0 - it will "reveal" the (purple) colourkey colour.
pThisDisplay->P3Overlay.rcDest.right = 2; } pThisDisplay->P3Overlay.rcSrc = *(DRVRECT*)&puod->rSrc;
pThisDisplay->dwOverlayFiltering = OVERLAY_FILTERING_X | OVERLAY_FILTERING_Y;
// See if this overlay size works by looking it up in the table.
iCurDotBandwidth = ( pThisDisplay->pGLInfo->PixelClockFrequency << pThisDisplay->pGLInfo->bPixelToBytesShift ) >> 10; iCurMemBandwidth = pThisDisplay->pGLInfo->MClkFrequency >> 10; iCurSourceWidth = ( puod->rSrc.right - puod->rSrc.left ) * ( pFormatOverlaySrc->dwBitsPerPixel >> 3 ); iCurWidthCoverage = ( ( puod->rDest.right - puod->rDest.left ) << 16 ) / ( pThisDisplay->pGLInfo->dwScreenWidth ); DISPDBG (( DBGLVL, "DdUpdateOverlay: Looking up mem=%d, pixel=%d, width=%d, coverage=0x%x", iCurMemBandwidth, iCurDotBandwidth, iCurSourceWidth, iCurWidthCoverage ));
iCurEntry = 0; // Search for a line with lower memory bandwidth and higher everything else.
while ( iCurEntry < SIZE_OF_OVERLAY_WORKS_TABLE ) { if (( OverlayWorksTable[iCurEntry].iMemBandwidth <= iCurMemBandwidth ) && ( OverlayWorksTable[iCurEntry].iDotBandwidth >= iCurDotBandwidth ) && ( OverlayWorksTable[iCurEntry].iSourceWidth >= iCurSourceWidth ) && ( OverlayWorksTable[iCurEntry].iWidthCoverage >= iCurWidthCoverage ) ) { // Yep - this should be alright then.
break; } iCurEntry++; } if ( iCurEntry == SIZE_OF_OVERLAY_WORKS_TABLE ) { // Oops - this will fall over when filtered.
DISPDBG((DBGLVL,"** P3RXOU32: overlay wanted mem=%d, pixel=%d, width=%d, coverage=0x%x", iCurMemBandwidth, iCurDotBandwidth, iCurSourceWidth, iCurWidthCoverage ));
// Normal behaviour.
bNoFilterInY = TRUE; } else { DISPDBG((DBGLVL,"** P3RXOU32: found mem=%d, pixel=%d, width=%d, coverage=0x%x", OverlayWorksTable[iCurEntry].iMemBandwidth, OverlayWorksTable[iCurEntry].iDotBandwidth, OverlayWorksTable[iCurEntry].iSourceWidth, OverlayWorksTable[iCurEntry].iWidthCoverage )); bNoFilterInY = FALSE; }
if ( bNoFilterInY ) { // Turn off Y filtering.
pThisDisplay->dwOverlayFiltering &= ~OVERLAY_FILTERING_Y; }
// Overlay is fine to show.
__OV_UpdatePosition(pThisDisplay, NULL);
_DD_OV_UpdateSource(pThisDisplay, puod->lpDDSrcSurface);
// Stride of source
LOAD_GLINT_CTRL_REG(VideoOverlayStride, DDSurf_GetPixelPitch(puod->lpDDSrcSurface)); LOAD_GLINT_CTRL_REG(VideoOverlayFieldOffset, 0x0); if ( puod->dwFlags & DDOVER_KEYDEST ) { // Use destination surface's destination colourkey for dst key.
dwDestColourKey = puod->lpDDDestSurface->ddckCKDestOverlay.dwColorSpaceLowValue; bDestColorKey = TRUE; }
if ( puod->dwFlags & DDOVER_KEYDESTOVERRIDE ) { // Use DDOVERLAYFX dest colour for dst key.
dwDestColourKey = puod->overlayFX.dckDestColorkey.dwColorSpaceLowValue; bDestColorKey = TRUE; } if ( puod->dwFlags & DDOVER_KEYSRC ) { // Use source surface's source colourkey for src key.
dwSrcColourKey = puod->lpDDSrcSurface->ddckCKSrcOverlay.dwColorSpaceLowValue; bSrcColorKey = TRUE; }
if ( puod->dwFlags & DDOVER_KEYSRCOVERRIDE ) { // Use DDOVERLAYFX src colour for src key.
dwSrcColourKey = puod->overlayFX.dckSrcColorkey.dwColorSpaceLowValue; bSrcColorKey = TRUE; }
if (bSrcColorKey && bDestColorKey) { // We can't do both - return an error.
puod->ddRVal = DDERR_OUTOFCAPS; return DDHAL_DRIVER_HANDLED; }
RDOverlayControl.Mode = VO_MODE_ALWAYS;
if (bSrcColorKey) { if (pFormatOverlaySrc->DeviceFormat == SURF_YUV422) { // Er... this is a very odd pixel format - how do I get a useful number out of it?
DISPDBG((ERRLVL,"** DdUpdateOverlay: no idea how to get a YUV422 source colour")); } else if (pFormatOverlaySrc->DeviceFormat == SURF_YUV444) { // No idea how to get a useful number out of this.
DISPDBG((ERRLVL,"** DdUpdateOverlay: no idea how to get a YUV444 source colour")); } else { switch (pFormatOverlaySrc->DitherFormat) { case P3RX_DITHERMODE_COLORFORMAT_CI: // Formatting already done.
break;
case P3RX_DITHERMODE_COLORFORMAT_332: dwSrcColourKey = FORMAT_332_32BIT_BGR(dwSrcColourKey); break;
case P3RX_DITHERMODE_COLORFORMAT_5551: dwSrcColourKey = FORMAT_5551_32BIT_BGR(dwSrcColourKey); break;
case P3RX_DITHERMODE_COLORFORMAT_4444: dwSrcColourKey = FORMAT_4444_32BIT_BGR(dwSrcColourKey); break;
case P3RX_DITHERMODE_COLORFORMAT_565: dwSrcColourKey = FORMAT_565_32BIT_BGR(dwSrcColourKey); break;
case P3RX_DITHERMODE_COLORFORMAT_8888: dwSrcColourKey = FORMAT_8888_32BIT_BGR(dwSrcColourKey); break;
default: DISPDBG((ERRLVL,"** DdUpdateOverlay: Unknown overlay pixel type")); break; } }
P3RD_LOAD_INDEX_REG(P3RD_VIDEO_OVERLAY_KEYR, (dwSrcColourKey & 0xFF)); P3RD_LOAD_INDEX_REG(P3RD_VIDEO_OVERLAY_KEYG, ((dwSrcColourKey >> 8) & 0xFF)); P3RD_LOAD_INDEX_REG(P3RD_VIDEO_OVERLAY_KEYB, ((dwSrcColourKey >> 16) & 0xFF));
RDOverlayControl.Mode = VO_MODE_OVERLAYKEY; }
if (bDestColorKey) {
switch (pFormatOverlayDest->dwBitsPerPixel) { case 8: P3RD_LOAD_INDEX_REG(P3RD_VIDEO_OVERLAY_KEYR, (dwDestColourKey & 0xFF)); P3RD_LOAD_INDEX_REG(P3RD_VIDEO_OVERLAY_KEYG, (dwDestColourKey & 0xFF)); P3RD_LOAD_INDEX_REG(P3RD_VIDEO_OVERLAY_KEYB, (dwDestColourKey & 0xFF)); break;
case 16: if (pFormatOverlayDest->DitherFormat == P3RX_DITHERMODE_COLORFORMAT_5551) { dwDestColourKey = FORMAT_5551_32BIT_BGR(dwDestColourKey); } else { dwDestColourKey = FORMAT_565_32BIT_BGR(dwDestColourKey); } P3RD_LOAD_INDEX_REG(P3RD_VIDEO_OVERLAY_KEYR, (dwDestColourKey & 0xFF)); P3RD_LOAD_INDEX_REG(P3RD_VIDEO_OVERLAY_KEYG, ((dwDestColourKey >> 8) & 0xFF)); P3RD_LOAD_INDEX_REG(P3RD_VIDEO_OVERLAY_KEYB, ((dwDestColourKey >> 16) & 0xFF)); break;
case 32: dwDestColourKey = FORMAT_8888_32BIT_BGR(dwDestColourKey); P3RD_LOAD_INDEX_REG(P3RD_VIDEO_OVERLAY_KEYR, (dwDestColourKey & 0xFF)); P3RD_LOAD_INDEX_REG(P3RD_VIDEO_OVERLAY_KEYG, ((dwDestColourKey >> 8) & 0xFF)); P3RD_LOAD_INDEX_REG(P3RD_VIDEO_OVERLAY_KEYB, ((dwDestColourKey >> 16) & 0xFF)); break;
default: break; }
RDOverlayControl.Mode = VO_MODE_MAINKEY; }
// Filtering
if ( ( pThisDisplay->dwOverlayFiltering & OVERLAY_FILTERING_X ) != 0 ) { if ( ( pThisDisplay->dwOverlayFiltering & OVERLAY_FILTERING_Y ) != 0 ) { // Full filtering.
OverlayMode.Filter = 1; } else { // In X only - no extra bandwidth problems.
// BUT THIS DOESN'T SEEM TO WORK IN SOME CASES - WE JUST GET NO FILTERING AT ALL!
OverlayMode.Filter = 2; } } else { // No filtering at all.
// (can't do Y filtering with no X filtering, but it never happens anyway).
OverlayMode.Filter = 0; }
if (puod->dwFlags & DDOVER_ALPHADESTCONSTOVERRIDE) { P3RD_LOAD_INDEX_REG(P3RD_VIDEO_OVERLAY_BLEND, puod->overlayFX.dwAlphaDestConst); RDOverlayControl.Mode = VO_MODE_BLEND; } }
// Load up the overlay mode
LOAD_GLINT_CTRL_REG(VideoOverlayMode, *(DWORD*)&OverlayMode);
// Setup the overlay control bits in the RAMDAC
P3RD_LOAD_INDEX_REG(P3RD_VIDEO_OVERLAY_CONTROL, *(BYTE*)&RDOverlayControl);
// Update the settings
UPDATE_OVERLAY(pThisDisplay, TRUE, TRUE);
puod->ddRVal = DD_OK; return DDHAL_DRIVER_HANDLED; } // DdUpdateOverlay
//-----------------------------------------------------------------------------
//
// DdSetOverlayPosition
//
// Sets the position for an overlay
//
// When the overlay is visible, the driver should cause the overlay to be
// displayed on the primary surface. The upper left corner of the overlay
// should be anchored at (lXPos,lYPos). For example, values of (0,0) indicates
// that the upper left corner of the overlay should appear in the upper left
// corner of the surface identified by lpDDDestSurface.
//
// When the overlay is invisible, the driver should set DDHAL_DRIVER_HANDLED in
// ddRVal and return.
//
// Parameters
//
// psopd
// Points to a DD_SETOVERLAYPOSITIONDATA structure that contains the
// information required to set the overlay position.
//
// .lpDD
// Points to a DD_DIRECTDRAW_GLOBAL structure that describes the
// driver.
// .lpDDSrcSurface
// Points to a DD_SURFACE_LOCAL structure that represents the
// DirectDraw overlay surface.
// .lpDDDestSurface
// Points to a DD_SURFACE_LOCAL structure representing the surface
// that is being overlaid.
// .lXPos
// Specifies the x coordinate of the upper left corner of the
// overlay, in pixels.
// .lYPos
// Specifies the y coordinate of the upper left corner of the
// overlay, in pixels.
// .ddRVal
// Specifies the location in which the driver writes the return
// value of the DdSetOverlayPosition callback. A return code of
// DD_OK indicates success.
// .SetOverlayPosition
// This is unused on Windows 2000.
//
//-----------------------------------------------------------------------------
DWORD CALLBACK DdSetOverlayPosition( LPDDHAL_SETOVERLAYPOSITIONDATA psopd) { P3_THUNKEDDATA* pThisDisplay; LONG lDestWidth; LONG lDestHeight; DWORD dwVideoOverlayUpdate; GET_THUNKEDDATA(pThisDisplay, psopd->lpDD);
DISPDBG ((DBGLVL,"**In DdSetOverlayPosition"));
if (pThisDisplay->P3Overlay.dwVisibleOverlays == 0) { psopd->ddRVal = DDERR_OVERLAYNOTVISIBLE; return DDHAL_DRIVER_HANDLED; } do { dwVideoOverlayUpdate = READ_GLINT_CTRL_REG(VideoOverlayUpdate); } while ((dwVideoOverlayUpdate & 0x1) != 0);
lDestWidth = pThisDisplay->P3Overlay.rcDest.right - pThisDisplay->P3Overlay.rcDest.left; lDestHeight = pThisDisplay->P3Overlay.rcDest.bottom - pThisDisplay->P3Overlay.rcDest.top;
// Keep the new position
pThisDisplay->P3Overlay.rcDest.left = psopd->lXPos; pThisDisplay->P3Overlay.rcDest.right = psopd->lXPos + (LONG)lDestWidth;
pThisDisplay->P3Overlay.rcDest.top = psopd->lYPos; pThisDisplay->P3Overlay.rcDest.bottom = psopd->lYPos + (LONG)lDestHeight; // Update the overlay position
__OV_UpdatePosition(pThisDisplay, NULL);
// Update the settings
LOAD_GLINT_CTRL_REG(VideoOverlayUpdate, VO_ENABLE);
psopd->ddRVal = DD_OK; return DDHAL_DRIVER_HANDLED;
} // DdSetOverlayPosition
|