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.
1412 lines
53 KiB
1412 lines
53 KiB
/******************************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
|
|
|
|
|