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.
2248 lines
81 KiB
2248 lines
81 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: mcd.c
|
|
*
|
|
* Main file for the Cirrus Logic 546X OpenGL MCD driver. This file contains
|
|
* the entry points needed for an MCD driver.
|
|
*
|
|
* (based on mcd.c from NT4.0 DDK)
|
|
*
|
|
* Copyright (c) 1996 Microsoft Corporation
|
|
* Copyright (c) 1997 Cirrus Logic, Inc.
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#include <excpt.h>
|
|
|
|
//#define DBGBRK
|
|
|
|
// uncomment the following to force render directly to visible frame
|
|
//#define FORCE_SINGLE_BUF
|
|
|
|
#if 0 // 1 here to avoid tons of prints for each texture load
|
|
#define MCDBG_PRINT_TEX
|
|
#else
|
|
#define MCDBG_PRINT_TEX MCDBG_PRINT
|
|
#endif
|
|
|
|
|
|
#include "mcdhw.h"
|
|
#include "mcdutil.h"
|
|
#include "mcdmath.h"
|
|
|
|
BOOL MCDrvInfo(MCDSURFACE *pMCDSurface, MCDDRIVERINFO *pMCDDriverInfo)
|
|
{
|
|
MCDBG_PRINT( "MCDrvInfo\n");
|
|
|
|
pMCDDriverInfo->verMajor = MCD_VER_MAJOR;
|
|
pMCDDriverInfo->verMinor = MCD_VER_MINOR;
|
|
pMCDDriverInfo->verDriver = 0x10000;
|
|
strcpy(pMCDDriverInfo->idStr, "Cirrus Logic 546X-Laguna3D (Cirrus Logic)");
|
|
pMCDDriverInfo->drvMemFlags = 0; // if not 0, can't fail any part of MCDrvDraw
|
|
pMCDDriverInfo->drvBatchMemSizeMax = 128000; // if 0, a default is used
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
#define TOTAL_PIXEL_FORMATS (2 * 2) // double-buffers * z-buffers
|
|
|
|
// Base color pixel formats
|
|
|
|
static DRVPIXELFORMAT drvFormats[] = { {8, 3, 3, 2, 0, 5, 2, 0, 0},// best except drawpix fails
|
|
//static DRVPIXELFORMAT drvFormats[] = { {8, 3, 3, 2, 0, 0, 3, 6, 0}, // change for drawpix at 8bpp (wrong for all else)
|
|
{16, 5, 5, 5, 0, 10, 5, 0, 0},
|
|
{16, 5, 6, 5, 0, 11, 5, 0, 0},
|
|
{24, 8, 8, 8, 0, 16, 8, 0, 0},
|
|
{32, 8, 8, 8, 0, 16, 8, 0, 0},
|
|
};
|
|
|
|
|
|
LONG MCDrvDescribePixelFormat(MCDSURFACE *pMCDSurface, LONG iPixelFormat,
|
|
ULONG nBytes, MCDPIXELFORMAT *pMCDPixelFormat,
|
|
ULONG flags)
|
|
{
|
|
BOOL zEnabled;
|
|
BOOL doubleBufferEnabled;
|
|
DRVPIXELFORMAT *pDrvPixelFormat;
|
|
PDEV *ppdev = (PDEV *)pMCDSurface->pso->dhpdev;
|
|
|
|
|
|
MCDBG_PRINT( "MCDrvDescribePixelFormat, ipixf=%d devid=%x\n",iPixelFormat,ppdev->dwLgDevID);
|
|
|
|
// return 0 here if no support at current bpp
|
|
if (ppdev->iBitmapFormat == BMF_24BPP) return 0;
|
|
// PDR 10892 - IBM doesn't like how OpenGL's stealing of the palette affects desktop colors
|
|
// Due to MCD design, there's no way around it in 8bpp, so we won't accelerate 8bpp
|
|
// Note that the 8bpp support has been left intact should we ever decide to reverse this decision
|
|
// To enable 8bpp, just remove the following line
|
|
if (ppdev->iBitmapFormat == BMF_8BPP) return 0;
|
|
|
|
if (!pMCDPixelFormat)
|
|
{
|
|
if (ppdev->iBitmapFormat == BMF_8BPP)
|
|
{
|
|
// for 8bpp, at hi-res with z enabled, it's quite possible z pitch
|
|
// requirement will exceed pitch, and MCDrvAllocBuffers will fail
|
|
// in that case, the CopyTexture part of mustpass.c will fail, even
|
|
// though punted to software. Otto Berkes of Microsoft agrees this
|
|
// could be an acceptable WHQL failure, but MS would need to verify
|
|
// the bug is in their code. Until then, the following is needed
|
|
// to pass WHQL ;(
|
|
// This says we don't support z buffering for hires 8bpp
|
|
if (ppdev->cxScreen >= 1152) // frido: this used to be >= 1280
|
|
return (TOTAL_PIXEL_FORMATS>>1);
|
|
else
|
|
return TOTAL_PIXEL_FORMATS;
|
|
}
|
|
else
|
|
{
|
|
return TOTAL_PIXEL_FORMATS;
|
|
}
|
|
}
|
|
|
|
|
|
if (iPixelFormat > TOTAL_PIXEL_FORMATS)
|
|
return 0;
|
|
|
|
iPixelFormat--;
|
|
|
|
// - see what possible vals for dwFlags is
|
|
// - looks like TOTAL_PIXEL_FORMATS is independent of color depths
|
|
// i.e. given a format like 332, how many permutations are supported
|
|
// - z, single/double, stencil, overlay, texture?
|
|
zEnabled = iPixelFormat >= (TOTAL_PIXEL_FORMATS / 2);
|
|
doubleBufferEnabled = (iPixelFormat % (TOTAL_PIXEL_FORMATS / 2) ) >=
|
|
(TOTAL_PIXEL_FORMATS / 4);
|
|
|
|
|
|
// NOTE: PFD_ defines are in \msdev\include\wingdi.h
|
|
|
|
pMCDPixelFormat->nSize = sizeof(MCDPIXELFORMAT);
|
|
pMCDPixelFormat->dwFlags = PFD_SWAP_COPY;
|
|
if (doubleBufferEnabled)
|
|
pMCDPixelFormat->dwFlags |= PFD_DOUBLEBUFFER;
|
|
pMCDPixelFormat->iPixelType = PFD_TYPE_RGBA;
|
|
|
|
MCDBG_PRINT( " DPIXFMT - no early ret: ppdev->bmf=%d zen=%d dbuf=%d ppd->flg=%x\n",ppdev->iBitmapFormat,zEnabled,doubleBufferEnabled,ppdev->flGreen);
|
|
|
|
// FUTURE: miniport only supports 888,565,indexed modes. Need 1555 mode as well?
|
|
// FUTURE: also, miniport 8 bit indexed supports set nbit rgb=6 each, not 332?
|
|
// FUTURE: I'll use the MGA stuff which had 332 for indexed, which is same a 5464 CGL.
|
|
// FUTURE: See ChoosePixelFormat in Win32 SDK - input is pixel depth only (8/16/24/32)
|
|
switch (ppdev->iBitmapFormat) {
|
|
default:
|
|
case BMF_8BPP:
|
|
// Need the palette. This will mess up the desktop, but OpenGL looks good
|
|
pDrvPixelFormat = &drvFormats[0];
|
|
pMCDPixelFormat->dwFlags |= (PFD_NEED_SYSTEM_PALETTE | PFD_NEED_PALETTE);
|
|
break;
|
|
case BMF_16BPP:
|
|
#ifdef _5464_1555_SUPPORT
|
|
if (ppdev->flGreen != 0x7e0) // not 565
|
|
pDrvPixelFormat = &drvFormats[1];
|
|
else
|
|
#endif //def _5464_1555_SUPPORT
|
|
pDrvPixelFormat = &drvFormats[2];
|
|
break;
|
|
// NOTE: We never get this far if 24bpp
|
|
case BMF_32BPP:
|
|
pDrvPixelFormat = &drvFormats[4];
|
|
break;
|
|
}
|
|
|
|
pMCDPixelFormat->cColorBits = pDrvPixelFormat->cColorBits;
|
|
pMCDPixelFormat->cRedBits = pDrvPixelFormat->rBits;
|
|
pMCDPixelFormat->cGreenBits = pDrvPixelFormat->gBits;
|
|
pMCDPixelFormat->cBlueBits = pDrvPixelFormat->bBits;
|
|
pMCDPixelFormat->cAlphaBits = pDrvPixelFormat->aBits;
|
|
pMCDPixelFormat->cRedShift = pDrvPixelFormat->rShift;
|
|
pMCDPixelFormat->cGreenShift = pDrvPixelFormat->gShift;
|
|
pMCDPixelFormat->cBlueShift = pDrvPixelFormat->bShift;
|
|
pMCDPixelFormat->cAlphaShift = pDrvPixelFormat->aShift;
|
|
|
|
if (zEnabled)
|
|
{
|
|
pMCDPixelFormat->cDepthBits = 16;
|
|
pMCDPixelFormat->cDepthBufferBits = 16;
|
|
pMCDPixelFormat->cDepthShift = 16;
|
|
}
|
|
else
|
|
{
|
|
pMCDPixelFormat->cDepthBits = 0;
|
|
pMCDPixelFormat->cDepthBufferBits = 0;
|
|
pMCDPixelFormat->cDepthShift = 0;
|
|
}
|
|
|
|
// FUTURE: cl546x stencil support could be added here
|
|
|
|
pMCDPixelFormat->cStencilBits = 0;
|
|
|
|
pMCDPixelFormat->cOverlayPlanes = 0;
|
|
pMCDPixelFormat->cUnderlayPlanes = 0;
|
|
pMCDPixelFormat->dwTransparentColor = 0;
|
|
|
|
return TOTAL_PIXEL_FORMATS;
|
|
}
|
|
|
|
BOOL MCDrvDescribeLayerPlane(MCDSURFACE *pMCDSurface,
|
|
LONG iPixelFormat, LONG iLayerPlane,
|
|
ULONG nBytes, MCDLAYERPLANE *pMCDLayerPlane,
|
|
ULONG flags)
|
|
{
|
|
MCDBG_PRINT( "MCDrvDescribeLayerPlane\n");
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
LONG MCDrvSetLayerPalette(MCDSURFACE *pMCDSurface, LONG iLayerPlane,
|
|
BOOL bRealize, LONG cEntries, COLORREF *pcr)
|
|
{
|
|
MCDBG_PRINT( "MCDrvSetLayerPalette\n");
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
HDEV MCDrvGetHdev(MCDSURFACE *pMCDSurface)
|
|
{
|
|
PDEV *ppdev = (PDEV *)pMCDSurface->pso->dhpdev;
|
|
|
|
MCDBG_PRINT( "MCDrvGetHdev\n");
|
|
|
|
return ppdev->hdevEng;
|
|
}
|
|
|
|
|
|
ULONG MCDrvCreateContext(MCDSURFACE *pMCDSurface, MCDRC *pMCDRc,
|
|
MCDRCINFO *pRcInfo)
|
|
{
|
|
DEVRC *pRc;
|
|
MCDWINDOW *pMCDWnd = pMCDSurface->pWnd;
|
|
DEVWND *pDevWnd;
|
|
PDEV *ppdev = (PDEV *)pMCDSurface->pso->dhpdev;
|
|
DRVPIXELFORMAT *pDrvPixelFormat;
|
|
MCDVERTEX *pv;
|
|
BOOL zEnabled;
|
|
BOOL doubleBufferEnabled;
|
|
ULONG i, maxVi;
|
|
|
|
MCDBG_PRINT( "MCDrvCreateContext\n");
|
|
|
|
// We only support window surfaces:
|
|
|
|
if (! (pMCDSurface->surfaceFlags & MCDSURFACE_HWND) )
|
|
return FALSE;
|
|
|
|
// no support on pre-5464 devices
|
|
if (ppdev->dwLgDevID == CL_GD5462)
|
|
return FALSE;
|
|
|
|
if ((pMCDRc->iPixelFormat > TOTAL_PIXEL_FORMATS) ||
|
|
(pMCDRc->iPixelFormat < 0)) {
|
|
MCDBG_PRINT( "MCDrvCreateContext: bad pixel format\n");
|
|
return FALSE;
|
|
}
|
|
|
|
// We don't support overlay planes:
|
|
|
|
if (pMCDRc->iLayerPlane)
|
|
return FALSE;
|
|
|
|
pRc = pMCDRc->pvUser = (DEVRC *)MCDAlloc(sizeof(DEVRC));
|
|
|
|
if (!pRc) {
|
|
MCDBG_PRINT("MCDrvCreateContext: couldn't allocate DEVRC\n");
|
|
return FALSE;
|
|
}
|
|
|
|
#ifdef DBGBRK
|
|
DBGBREAKPOINT();
|
|
#endif
|
|
|
|
zEnabled = (pMCDRc->iPixelFormat - 1) >= (TOTAL_PIXEL_FORMATS / 2);
|
|
doubleBufferEnabled = ((pMCDRc->iPixelFormat - 1) % (TOTAL_PIXEL_FORMATS / 2) ) >=
|
|
(TOTAL_PIXEL_FORMATS / 4);
|
|
|
|
pRc->zBufEnabled = zEnabled;
|
|
pRc->backBufEnabled = doubleBufferEnabled;
|
|
|
|
// If we're not yet tracking this window, allocate the per-window DEVWND
|
|
// structure for maintaining per-window info such as front/back/z buffer
|
|
// resources:
|
|
|
|
if (!pMCDWnd->pvUser) {
|
|
pDevWnd = pMCDWnd->pvUser = (DEVWND *)MCDAlloc(sizeof(DEVWND));
|
|
if (!pDevWnd) {
|
|
MCDFree(pMCDRc->pvUser);
|
|
pMCDRc->pvUser = NULL;
|
|
MCDBG_PRINT("MCDrvCreateContext: couldn't allocate DEVWND");
|
|
return FALSE;
|
|
}
|
|
pDevWnd->createFlags = pMCDRc->createFlags;
|
|
pDevWnd->iPixelFormat = pMCDRc->iPixelFormat;
|
|
// init ptrs so we know back and z buffers don't exist yet
|
|
pDevWnd->pohZBuffer = NULL;
|
|
pDevWnd->pohBackBuffer = NULL;
|
|
pDevWnd->dispUnique = ppdev->iUniqueness;
|
|
} else {
|
|
|
|
// We already have a per-window DEVWND structure tracking this window.
|
|
// In this case, do a sanity-check on the pixel format for this
|
|
// context, since a window's pixel format can not change once it has been
|
|
// set (by the first context bound to the window). So, if the pixel
|
|
// format for the incoming context doesn't match the current pixel
|
|
// format for the window, we have to fail context creation:
|
|
|
|
pDevWnd = pMCDWnd->pvUser;
|
|
|
|
if (pDevWnd->iPixelFormat != pMCDRc->iPixelFormat) {
|
|
MCDFree(pMCDRc->pvUser);
|
|
pMCDRc->pvUser = NULL;
|
|
MCDBG_PRINT("MCDrvCreateContext: mismatched pixel formats, window = %d, context = %d",
|
|
pDevWnd->iPixelFormat, pMCDRc->iPixelFormat);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
pRc->pEnumClip = pMCDSurface->pWnd->pClip;
|
|
|
|
// Set up our color scale values so that color components are
|
|
// normalized to 0..7fffff
|
|
|
|
// NOTE: MGA normalizes colors to 0..7f,ffff -> 5464 needs 0->ff,ffff
|
|
|
|
// We also need to make sure we don't fault due to bad FL data as well...
|
|
try {
|
|
|
|
if (pRcInfo->redScale != (MCDFLOAT)0.0)
|
|
pRc->rScale = (MCDFLOAT)(0xffffff) / pRcInfo->redScale;
|
|
else
|
|
pRc->rScale = (MCDFLOAT)0.0;
|
|
|
|
if (pRcInfo->greenScale != (MCDFLOAT)0.0)
|
|
pRc->gScale = (MCDFLOAT)(0xffffff) / pRcInfo->greenScale;
|
|
else
|
|
pRc->gScale = (MCDFLOAT)0.0;
|
|
|
|
if (pRcInfo->blueScale != (MCDFLOAT)0.0)
|
|
pRc->bScale = (MCDFLOAT)(0xffffff) / pRcInfo->blueScale;
|
|
else
|
|
pRc->bScale = (MCDFLOAT)0.0;
|
|
|
|
if (pRcInfo->alphaScale != (MCDFLOAT)0.0)
|
|
pRc->aScale = (MCDFLOAT)(0xffff00) / pRcInfo->alphaScale;
|
|
else
|
|
pRc->aScale = (MCDFLOAT)0.0;
|
|
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
MCDBG_PRINT("!!Exception in MCDrvCreateContext!!");
|
|
return FALSE;
|
|
}
|
|
|
|
pRc->zScale = (MCDFLOAT)65535.0;
|
|
|
|
pRc->pickNeeded = TRUE; // We'll definitely need to re-pick
|
|
// our rendering functions
|
|
// Initialize the pColor pointer in the clip buffer:
|
|
|
|
for (i = 0, pv = &pRc->clipTemp[0],
|
|
maxVi = sizeof(pRc->clipTemp) / sizeof(MCDVERTEX);
|
|
i < maxVi; i++, pv++) {
|
|
pv->pColor = &pv->colors[__MCD_FRONTFACE];
|
|
}
|
|
|
|
// Set up those rendering functions which are state-invariant:
|
|
pRc->clipLine = __MCDClipLine;
|
|
pRc->clipTri = __MCDClipTriangle;
|
|
pRc->clipPoly = __MCDClipPolygon;
|
|
pRc->doClippedPoly = __MCDDoClippedPolygon;
|
|
|
|
pRc->viewportXAdjust = pRcInfo->viewportXAdjust;
|
|
pRc->viewportYAdjust = pRcInfo->viewportYAdjust;
|
|
|
|
#ifdef TEST_REQ_FLAGS
|
|
pRcInfo->requestFlags = MCDRCINFO_NOVIEWPORTADJUST |
|
|
MCDRCINFO_Y_LOWER_LEFT |
|
|
MCDRCINFO_DEVCOLORSCALE |
|
|
MCDRCINFO_DEVZSCALE;
|
|
|
|
pRcInfo->redScale = (MCDFLOAT)1.0;
|
|
pRcInfo->greenScale = (MCDFLOAT)1.0;
|
|
pRcInfo->blueScale = (MCDFLOAT)1.0;
|
|
pRcInfo->alphaScale = (MCDFLOAT)1.0;
|
|
|
|
pRcInfo->zScale = 0.99991;
|
|
#endif
|
|
|
|
pRc->dwControl0 = 0;
|
|
pRc->Control0.Alpha_Mode = LL_ALPHA_INTERP; // alpha blend and fog both use interpolated alpha
|
|
pRc->Control0.Light_Src_Sel = LL_LIGHTING_INTERP_RGB; // use poly engine output for light source
|
|
switch( ppdev->iBitmapFormat )
|
|
{
|
|
case BMF_8BPP: pRc->Control0.Pixel_Mode = PIXEL_MODE_332; break;
|
|
case BMF_16BPP: pRc->Control0.Pixel_Mode = PIXEL_MODE_565; break;
|
|
//case BMF_24BPP: - 3d engine has no support for 24 bit
|
|
case BMF_32BPP: pRc->Control0.Pixel_Mode = PIXEL_MODE_A888; break;
|
|
}
|
|
|
|
pRc->dwTxControl0=0;
|
|
#if DRIVER_5465
|
|
pRc->TxControl0.UV_Precision = 1;
|
|
#endif
|
|
pRc->TxControl0.Tex_Mask_Polarity = 1; // non-zero mask bit in texel will draw
|
|
|
|
|
|
pRc->dwTxXYBase=0;
|
|
pRc->dwColor0=0;
|
|
|
|
SETREG_NC( CONTROL0_3D, pRc->dwControl0 );
|
|
SETREG_NC( TX_CTL0_3D, pRc->dwTxControl0 );
|
|
SETREG_NC( TX_XYBASE_3D, pRc->dwTxXYBase );
|
|
SETREG_NC( COLOR0_3D, pRc->dwColor0 );
|
|
|
|
pRc->pLastDevWnd = NULL;
|
|
pRc->pLastTexture = TEXTURE_NOT_LOADED;
|
|
pRc->fNumDraws = (float)0.0;
|
|
pRc->punt_front_w_windowed_z = FALSE;
|
|
ppdev->LL_State.pattern_ram_state = PATTERN_RAM_INVALID;
|
|
ppdev->pLastDevRC = (ULONG)NULL;
|
|
ppdev->NumMCDContexts++;
|
|
|
|
MCDBG_PRINT( "MCDrvCreateContext - returns successfully\n");
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
VOID FASTCALL __MCDDummyProc(DEVRC *pRc)
|
|
{
|
|
MCDBG_PRINT( "MCDDummyProc (render support routine)\n");
|
|
}
|
|
|
|
ULONG MCDrvDeleteContext(MCDRC *pRc, DHPDEV dhpdev)
|
|
{
|
|
PDEV *ppdev = (PDEV *)dhpdev;
|
|
|
|
MCDBG_PRINT( "MCDrvDeleteContext, num contexts left after this delete = %d\n",ppdev->NumMCDContexts-1);
|
|
|
|
WAIT_HW_IDLE(ppdev);
|
|
|
|
if (pRc->pvUser) {
|
|
MCDFree(pRc->pvUser);
|
|
pRc->pvUser = NULL;
|
|
}
|
|
|
|
if (ppdev->NumMCDContexts>0) ppdev->NumMCDContexts--;
|
|
|
|
return (ULONG)TRUE;
|
|
}
|
|
|
|
|
|
ULONG MCDrvBindContext(MCDSURFACE *pMCDSurface, MCDRC *pMCDRc)
|
|
{
|
|
DEVWND *pDevWnd = (DEVWND *)(pMCDSurface->pWnd->pvUser);
|
|
PDEV *ppdev = (PDEV *)pMCDSurface->pso->dhpdev;
|
|
|
|
DEVRC *pRc = pMCDRc->pvUser;
|
|
|
|
MCDBG_PRINT( "MCDrvBindContext\n");
|
|
|
|
// OK, this is a new binding, so create the per-window structure and
|
|
// set the pixel format:
|
|
|
|
if (!pDevWnd) {
|
|
|
|
pDevWnd = pMCDSurface->pWnd->pvUser = (DEVWND *)MCDAlloc(sizeof(DEVWND));
|
|
if (!pDevWnd) {
|
|
MCDBG_PRINT( "MCDrvBindContext: couldn't allocate DEVWND");
|
|
return FALSE;
|
|
}
|
|
pDevWnd->createFlags = pMCDRc->createFlags;
|
|
pDevWnd->iPixelFormat = pMCDRc->iPixelFormat;
|
|
// init ptrs so we know back and z buffers don't exist yet
|
|
pDevWnd->pohZBuffer = NULL;
|
|
pDevWnd->pohBackBuffer = NULL;
|
|
|
|
pDevWnd->dispUnique = ppdev->iUniqueness;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
if (pMCDRc->iPixelFormat != pDevWnd->iPixelFormat) {
|
|
MCDBG_PRINT( "MCDrvBindContext: tried to bind unmatched pixel formats");
|
|
return FALSE;
|
|
}
|
|
|
|
// 5464 doesn't need this....
|
|
//HWUpdateBufferPos(pMCDSurface->pWnd, pMCDSurface->pso, TRUE);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
ULONG MCDrvAllocBuffers(MCDSURFACE *pMCDSurface, MCDRC *pMCDRc)
|
|
{
|
|
DEVRC *pRc = (DEVRC *)pMCDRc->pvUser;
|
|
MCDWINDOW *pMCDWnd = pMCDSurface->pWnd;
|
|
DEVWND *pDevWnd = (DEVWND *)(pMCDSurface->pWnd->pvUser);
|
|
BOOL bZBuffer = (pDevWnd->pohZBuffer != NULL);
|
|
BOOL bBackBuffer = (pDevWnd->pohBackBuffer != NULL);
|
|
ULONG ret;
|
|
PDEV *ppdev = (PDEV *)pMCDSurface->pso->dhpdev;
|
|
|
|
MCDBG_PRINT( "MCDrvAllocBuffers\n");
|
|
|
|
|
|
// Reject the call if we've already done an allocation for this window:
|
|
|
|
if ((bZBuffer || bBackBuffer) &&
|
|
((DEVWND *)pMCDWnd->pvUser)->dispUnique == GetDisplayUniqueness((PDEV *)pMCDSurface->pso->dhpdev)) {
|
|
|
|
MCDBG_PRINT( "MCDrvAllocBuffers - realloc attempt\n");
|
|
ret = (bZBuffer == pRc->zBufEnabled) &&
|
|
(bBackBuffer == pRc->backBufEnabled);
|
|
MCDBG_PRINT( "MCDrvAllocBuffers ret=%d\n",ret);
|
|
return ret;
|
|
}
|
|
|
|
// Update the display resolution uniqueness for this window:
|
|
|
|
((DEVWND *)pMCDWnd->pvUser)->dispUnique = GetDisplayUniqueness((PDEV *)pMCDSurface->pso->dhpdev);
|
|
|
|
// indicate in DEVWND if z,back buffers wanted in case window size increase such that
|
|
// re-alloc in MCDrvTrackWindow fails, and later window reduced so that buffers would fit
|
|
// without this, there's no way for DEVWND to remember what buffers are really wanted
|
|
// if some intermediate re-alloc fails.
|
|
pDevWnd->bDesireZBuffer = pRc->zBufEnabled;
|
|
pDevWnd->bDesireBackBuffer = pRc->backBufEnabled;
|
|
|
|
ret = (ULONG)HWAllocResources(pMCDSurface->pWnd, pMCDSurface->pso,
|
|
pRc->zBufEnabled, pRc->backBufEnabled);
|
|
|
|
pDevWnd->dwBase0 = 0;
|
|
pDevWnd->dwBase1 = 0;
|
|
|
|
// setup 546x buffer pointers to z and back buffers here
|
|
if (pRc->zBufEnabled && !pDevWnd->pohZBuffer)
|
|
ret=FALSE;
|
|
else if (pRc->zBufEnabled) {
|
|
// FUTURE: z buffer location assumed to be in RDRAM - if buffer in system, need to change setup
|
|
// FUTURE: see setup in LL_SetZBuffer in l3d\source\control.c
|
|
|
|
pDevWnd->Base1.Z_Buffer_Y_Offset = pDevWnd->pohZBuffer->aligned_y >> 5;
|
|
|
|
// MCD_QST2: if global full screen z buffer, clearing affects context established earlier.
|
|
// MCD_QST2: IS THAT OK?
|
|
// init z buffer to all 0xFF's, since GL z compare typically GL_LESS
|
|
// NOTE that size is not full buffer size, since alignment restrictions may force top of
|
|
// actual buffer to be down from top
|
|
memset( ppdev->pjScreen + (pDevWnd->pohZBuffer->y * ppdev->lDeltaScreen),
|
|
0xff,
|
|
((pDevWnd->pohZBuffer->y+pDevWnd->pohZBuffer->sizey) //size = end...
|
|
-pDevWnd->pohZBuffer->aligned_y) // minus top...
|
|
* ppdev->lDeltaScreen ); // times pitch
|
|
}
|
|
|
|
if (pRc->backBufEnabled && !pDevWnd->pohBackBuffer)
|
|
ret=FALSE;
|
|
else if (pRc->backBufEnabled) {
|
|
|
|
#ifndef FORCE_SINGLE_BUF
|
|
pDevWnd->Base1.Color_Buffer_Y_Offset = pDevWnd->pohBackBuffer->aligned_y >> 5;
|
|
pDevWnd->Base0.Color_Buffer_X_Offset = pDevWnd->pohBackBuffer->aligned_x >> 6;
|
|
#endif // ndef FORCE_SINGLE_BUF
|
|
|
|
}
|
|
|
|
if (ret)
|
|
{
|
|
if (pDevWnd->pohBackBuffer && pDevWnd->pohZBuffer)
|
|
{
|
|
// both buffers alloc'd
|
|
MCDBG_PRINT("FB at %x, FBlen=%x, FBhi=%x start OffSc at %x, Z offset = %x, backbuf offset = %x\n",
|
|
ppdev->pjScreen,ppdev->lTotalMem,ppdev->cyScreen,ppdev->pjOffScreen,
|
|
pDevWnd->pohZBuffer->aligned_y,pDevWnd->pohBackBuffer->aligned_y);
|
|
}
|
|
else if (pDevWnd->pohBackBuffer)
|
|
{
|
|
// only back buffer alloc'd
|
|
MCDBG_PRINT("FB at %x, FBlen=%x, FBhi=%x start OffSc at %x, NO ZBUF, backbuf offset = %x\n",
|
|
ppdev->pjScreen,ppdev->lTotalMem,ppdev->cyScreen,ppdev->pjOffScreen,
|
|
pDevWnd->pohBackBuffer->aligned_y);
|
|
}
|
|
else if (pDevWnd->pohZBuffer)
|
|
{
|
|
// only Z buffer alloc'd
|
|
MCDBG_PRINT("FB at %x, FBlen=%x, FBhi=%x start OffSc at %x, Z offset = %x, NO BACKBUF\n",
|
|
ppdev->pjScreen,ppdev->lTotalMem,ppdev->cyScreen,ppdev->pjOffScreen,
|
|
pDevWnd->pohZBuffer->aligned_y);
|
|
}
|
|
else
|
|
{
|
|
// no buffers alloc'd
|
|
MCDBG_PRINT("FB at %x, FBlen=%x, FBhi=%x start OffSc at %x, NO ZBUF , NO BACKBUF\n",
|
|
ppdev->pjScreen,ppdev->lTotalMem,ppdev->cyScreen,ppdev->pjOffScreen);
|
|
}
|
|
|
|
SETREG_NC( BASE0_ADDR_3D, pDevWnd->dwBase0 );
|
|
SETREG_NC( BASE1_ADDR_3D, pDevWnd->dwBase1 );
|
|
|
|
pRc->pLastDevWnd = pDevWnd;
|
|
|
|
MCDBG_PRINT( "MCDrvAllocBuffers ret=%d\n",ret);
|
|
}
|
|
else
|
|
{
|
|
pRc->pLastDevWnd = NULL;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
ULONG MCDrvGetBuffers(MCDSURFACE *pMCDSurface, MCDRC *pMCDRc,
|
|
MCDBUFFERS *pMCDBuffers)
|
|
{
|
|
DEVRC *pRc = (DEVRC *)pMCDRc->pvUser;
|
|
MCDWINDOW *pMCDWnd = pMCDSurface->pWnd;
|
|
DEVWND *pDevWnd = (DEVWND *)(pMCDSurface->pWnd->pvUser);
|
|
PDEV *ppdev = (PDEV *)pMCDSurface->pso->dhpdev;
|
|
|
|
MCDBG_PRINT("MCDrvGetBuffers");
|
|
|
|
MCD_CHECK_BUFFERS_VALID(pMCDSurface, pRc, FALSE);
|
|
|
|
pMCDBuffers->mcdFrontBuf.bufFlags = MCDBUF_ENABLED;
|
|
pMCDBuffers->mcdFrontBuf.bufOffset =
|
|
(pMCDWnd->clientRect.top * ppdev->lDeltaScreen) +
|
|
(pMCDWnd->clientRect.left * ppdev->iBytesPerPixel);
|
|
pMCDBuffers->mcdFrontBuf.bufStride = ppdev->lDeltaScreen;
|
|
|
|
if (pDevWnd->bValidBackBuffer) {
|
|
pMCDBuffers->mcdBackBuf.bufFlags = MCDBUF_ENABLED;
|
|
|
|
if ((ppdev->cDoubleBufferRef == 1) || (pMCDWnd->pClip->c == 1))
|
|
pMCDBuffers->mcdBackBuf.bufFlags |= MCDBUF_NOCLIP;
|
|
#ifndef FORCE_SINGLE_BUF
|
|
if (ppdev->pohBackBuffer == pDevWnd->pohBackBuffer) {
|
|
// offset from screen origin
|
|
pMCDBuffers->mcdBackBuf.bufOffset =
|
|
(pMCDWnd->clientRect.top * ppdev->lDeltaScreen) +
|
|
(pMCDWnd->clientRect.left * ppdev->iBytesPerPixel) + pDevWnd->backBufferOffset;
|
|
} else {
|
|
// offset from window origin
|
|
pMCDBuffers->mcdBackBuf.bufOffset = pDevWnd->backBufferOffset;
|
|
}
|
|
#else // FORCE_SINGLE_BUF
|
|
pMCDBuffers->mcdBackBuf.bufOffset = pMCDBuffers->mcdFrontBuf.bufOffset;
|
|
#endif // FORCE_SINGLE_BUF
|
|
|
|
} else {
|
|
pMCDBuffers->mcdBackBuf.bufFlags = 0;
|
|
}
|
|
|
|
pMCDBuffers->mcdBackBuf.bufStride = ppdev->lDeltaScreen;
|
|
|
|
|
|
if (pDevWnd->bValidZBuffer) {
|
|
pMCDBuffers->mcdDepthBuf.bufFlags = MCDBUF_ENABLED;
|
|
|
|
if ((ppdev->cZBufferRef == 1) || (pMCDWnd->pClip->c == 1))
|
|
pMCDBuffers->mcdDepthBuf.bufFlags |= MCDBUF_NOCLIP;
|
|
|
|
if (ppdev->pohZBuffer == pDevWnd->pohZBuffer) {
|
|
// offset from screen origin
|
|
// NOTE: the mult by 2 below is because Z is always 2 byte/pix
|
|
pMCDBuffers->mcdDepthBuf.bufOffset =
|
|
(pMCDWnd->clientRect.top * ppdev->lDeltaScreen) +
|
|
(pMCDWnd->clientRect.left * 2) + pDevWnd->zBufferOffset;
|
|
|
|
} else {
|
|
// offset from window origin
|
|
// NOTE: the mult by 2 below is because Z is always 2 byte/pix
|
|
pMCDBuffers->mcdDepthBuf.bufOffset = pDevWnd->zBufferOffset;
|
|
}
|
|
|
|
} else {
|
|
pMCDBuffers->mcdDepthBuf.bufFlags = 0;
|
|
}
|
|
|
|
//NOTE: z stride same as frame stride on 546x
|
|
pMCDBuffers->mcdDepthBuf.bufStride = ppdev->lDeltaScreen;
|
|
|
|
return (ULONG)TRUE;
|
|
}
|
|
|
|
|
|
ULONG MCDrvSwap(MCDSURFACE *pMCDSurface, ULONG flags)
|
|
{
|
|
MCDWINDOW *pWnd;
|
|
ULONG cClip;
|
|
RECTL *pClip;
|
|
PDEV *ppdev = (PDEV *)pMCDSurface->pso->dhpdev;
|
|
DEVWND *pDevWnd = (DEVWND *)(pMCDSurface->pWnd->pvUser);
|
|
|
|
MCDBG_PRINT("MCDrvSwap");
|
|
|
|
pWnd = pMCDSurface->pWnd;
|
|
|
|
// If we're not tracking this window, just return...
|
|
|
|
if (!pWnd) {
|
|
MCDBG_PRINT("MCDrvSwap: trying to swap an untracked window");\
|
|
return FALSE;
|
|
}
|
|
|
|
if (!pDevWnd) {
|
|
MCDBG_PRINT("MCDrvSwap: NULL buffers.");\
|
|
return FALSE;
|
|
}
|
|
|
|
if (!pDevWnd->bValidBackBuffer) {
|
|
MCDBG_PRINT("MCDrvSwap: back buffer invalid");
|
|
return FALSE;
|
|
}
|
|
|
|
if (pDevWnd->dispUnique != GetDisplayUniqueness(ppdev)) {
|
|
MCDBG_PRINT("MCDrvSwap: resolution changed but not updated");
|
|
return FALSE;
|
|
}
|
|
|
|
// Just return if we have nothing to swap:
|
|
//
|
|
// - no visible rectangle
|
|
// - per-plane swap, but none of the specified planes
|
|
// are supported by driver
|
|
|
|
if (!(cClip = pWnd->pClipUnscissored->c) ||
|
|
(flags && !(flags & MCDSWAP_MAIN_PLANE)))
|
|
return TRUE;
|
|
|
|
#ifndef FORCE_SINGLE_BUF
|
|
for (pClip = &pWnd->pClipUnscissored->arcl[0]; cClip; cClip--,
|
|
pClip++)
|
|
{
|
|
// Do the fill:
|
|
HW_COPY_RECT(pMCDSurface, pClip);
|
|
}
|
|
#endif // ndef FORCE_SINGLE_BUF
|
|
|
|
return (ULONG)TRUE;
|
|
}
|
|
|
|
|
|
ULONG MCDrvState(MCDSURFACE *pMCDSurface, MCDRC *pMCDRc, MCDMEM *pMCDMem,
|
|
UCHAR *pStart, LONG length, ULONG numStates)
|
|
{
|
|
DEVRC *pRc = (DEVRC *)pMCDRc->pvUser;
|
|
MCDSTATE *pState = (MCDSTATE *)pStart;
|
|
MCDSTATE *pStateEnd = (MCDSTATE *)(pStart + length);
|
|
|
|
MCDBG_PRINT("MCDrvState");
|
|
|
|
MCD_CHECK_RC(pRc);
|
|
|
|
while (pState < pStateEnd) {
|
|
|
|
if (((UCHAR *)pStateEnd - (UCHAR *)pState) < sizeof(MCDSTATE)) {
|
|
MCDBG_PRINT("MCDrvState: buffer too small");
|
|
return FALSE;
|
|
}
|
|
|
|
switch (pState->state) {
|
|
case MCD_RENDER_STATE:
|
|
if (((UCHAR *)pState + sizeof(MCDRENDERSTATE)) >
|
|
(UCHAR *)pStateEnd)
|
|
return FALSE;
|
|
|
|
memcpy(&pRc->MCDState, &pState->stateValue,
|
|
sizeof(MCDRENDERSTATE));
|
|
|
|
// Flag the fact that we need to re-pick the
|
|
// rendering functions:
|
|
|
|
pRc->pickNeeded = TRUE;
|
|
pRc->MCDState.zOffsetUnits *= (float)100.0;
|
|
|
|
pState = (MCDSTATE *)((UCHAR *)pState + sizeof(MCDSTATE_RENDER));
|
|
break;
|
|
|
|
case MCD_PIXEL_STATE:
|
|
// Not accelerated in this driver, so we can ignore this state
|
|
// (which implies that we do not need to set the pick flag).
|
|
// FUTURE: MCDPIXELSTATE ignored - used by MCDDraw/Read/CopyPixels
|
|
// FUTURE: MGA doesn't accelerate - 546x may want to some day
|
|
|
|
pState = (MCDSTATE *)((UCHAR *)pState + sizeof(MCDSTATE_PIXEL));
|
|
break;
|
|
|
|
case MCD_SCISSOR_RECT_STATE:
|
|
// Not needed in this driver, so we can ignore this state
|
|
// (which implies that we do not need to set the pick flag).
|
|
// FUTURE: MCDSCISSORRECTSTATE ignored - not mentioned in MCD spec
|
|
// FUTURE: MGA doesn't accelerate - 546x may want to some day???
|
|
|
|
pState = (MCDSTATE *)((UCHAR *)pState + sizeof(MCDSTATE_SCISSOR_RECT));
|
|
break;
|
|
|
|
case MCD_TEXENV_STATE:
|
|
|
|
if (((UCHAR *)pState + sizeof(MCDSTATE_TEXENV)) >
|
|
(UCHAR *)pStateEnd)
|
|
return FALSE;
|
|
|
|
memcpy(&pRc->MCDTexEnvState, &pState->stateValue,
|
|
sizeof(MCDTEXENVSTATE));
|
|
|
|
// Flag the fact that we need to re-pick the
|
|
// rendering functions:
|
|
|
|
pRc->pickNeeded = TRUE;
|
|
|
|
pState = (MCDSTATE *)((UCHAR *)pState + sizeof(MCDSTATE_TEXENV));
|
|
break;
|
|
|
|
default:
|
|
MCDBG_PRINT("MCDrvState: Unrecognized state %d.", pState->state);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return (ULONG)TRUE;
|
|
}
|
|
|
|
|
|
ULONG MCDrvViewport(MCDSURFACE *pMCDSurface, MCDRC *pMCDRc,
|
|
MCDVIEWPORT *pMCDViewport)
|
|
{
|
|
DEVRC *pRc = (DEVRC *)pMCDRc->pvUser;
|
|
|
|
MCDBG_PRINT("MCDrvViewport");
|
|
|
|
MCD_CHECK_RC(pRc);
|
|
|
|
pRc->MCDViewport = *pMCDViewport;
|
|
|
|
return (ULONG)TRUE;
|
|
}
|
|
|
|
|
|
VOID MCDrvTrackWindow(WNDOBJ *pWndObj, MCDWINDOW *pMCDWnd, ULONG flags)
|
|
{
|
|
SURFOBJ *pso = pWndObj->psoOwner;
|
|
PDEV *ppdev = (PDEV *)pso->dhpdev;
|
|
|
|
MCDBG_PRINT( "MCDrvTrackWindow, flags=%x\n",flags);
|
|
|
|
//
|
|
// Note: pMCDWnd is NULL for surface notifications, so if needed
|
|
// they should be handled before this check:
|
|
//
|
|
|
|
if (!pMCDWnd)
|
|
return;
|
|
|
|
if (!pMCDWnd->pvUser) {
|
|
MCDBG_PRINT("MCDrvTrackWindow: NULL pDevWnd");
|
|
return;
|
|
}
|
|
|
|
// MCD_QST2: should we reset more than ppdev->LL_State.pRegs at top of TrackWindow
|
|
// MCD_QST2: when uniqueness has changed?? - see CLMCDInit in enable.c
|
|
ppdev->LL_State.pRegs = (DWORD *)ppdev->pLgREGS;
|
|
|
|
WAIT_HW_IDLE(ppdev);
|
|
|
|
switch (flags) {
|
|
case WOC_DELETE:
|
|
|
|
MCDBG_PRINT("MCDrvTrackWindow: WOC_DELETE");
|
|
|
|
// If the display resoultion has changed, the resources we had
|
|
// bound to the tracked window are gone, so don't try to delete
|
|
// the back- and z-buffer resources which are no longer present:
|
|
if (((DEVWND *)pMCDWnd->pvUser)->dispUnique == GetDisplayUniqueness((PDEV *)(pso->dhpdev)))
|
|
{
|
|
HWFreeResources(pMCDWnd, pso);
|
|
}
|
|
|
|
MCDFree((VOID *)pMCDWnd->pvUser);
|
|
pMCDWnd->pvUser = NULL;
|
|
|
|
break;
|
|
|
|
case WOC_RGN_CLIENT:
|
|
|
|
// The resources we had bound to the tracked window have moved,
|
|
// so update them:
|
|
MCDBG_PRINT("MCDrvTrackWindow: WOC_RGN_CLIENT");
|
|
|
|
{
|
|
DEVWND *pWnd = (DEVWND *)pMCDWnd->pvUser;
|
|
BOOL bZBuffer = pWnd->bDesireZBuffer;
|
|
BOOL bBackBuffer = pWnd->bDesireBackBuffer;
|
|
PDEV *ppdev = (PDEV *)pso->dhpdev;
|
|
ULONG height = pMCDWnd->clientRect.bottom - pMCDWnd->clientRect.top;
|
|
ULONG width = pMCDWnd->clientRect.right - pMCDWnd->clientRect.left;
|
|
BOOL bWindowBuffer =
|
|
(bZBuffer && !ppdev->pohZBuffer) ||
|
|
(bBackBuffer && !ppdev->pohBackBuffer);
|
|
|
|
// If the window is using a window-sized back/z resource, we need to
|
|
// reallocate it if there has been a size change (or if reset)
|
|
int need_new_resources =
|
|
((((height != pWnd->allocatedBufferHeight) ||
|
|
(width != pWnd->allocatedBufferWidth)) &&
|
|
bWindowBuffer) || (pWnd->dispUnique != GetDisplayUniqueness(ppdev))) ? 1 : 0;
|
|
|
|
if (need_new_resources)
|
|
{
|
|
|
|
// free current resources (unless reset, in which case resources are already gone)
|
|
if (pWnd->dispUnique == GetDisplayUniqueness(ppdev))
|
|
{
|
|
MCDBG_PRINT(" WOC_RGN_CLIENT: freeing resources");
|
|
HWFreeResources(pMCDWnd, pso);
|
|
}
|
|
else
|
|
{
|
|
// recent reset, so associate new uniqueness with current window
|
|
pWnd->dispUnique = GetDisplayUniqueness((PDEV *)pso->dhpdev);
|
|
}
|
|
|
|
MCDBG_PRINT(" WOC_RGN_CLIENT: alloc'ing new resources");
|
|
|
|
if ( HWAllocResources(pMCDWnd, pso, bZBuffer, bBackBuffer) )
|
|
{
|
|
MCDBG_PRINT(" WOC_RGN_CLIENT: alloc of new resources WORKED");
|
|
// setup 546x buffer pointers to z and back buffers here
|
|
if (pWnd->pohZBuffer)
|
|
{
|
|
// FUTURE: z buffer location assumed to be in RDRAM - if buffer in system, need to change setup
|
|
// FUTURE: see setup in LL_SetZBuffer in l3d\source\control.c
|
|
|
|
pWnd->Base1.Z_Buffer_Y_Offset = pWnd->pohZBuffer->aligned_y >> 5;
|
|
|
|
// init z buffer to all 0xFF's, since GL z compare typically GL_LESS
|
|
memset( ppdev->pjScreen + (pWnd->pohZBuffer->aligned_y * ppdev->lDeltaScreen),
|
|
0xff,
|
|
pWnd->pohZBuffer->sizey * ppdev->lDeltaScreen );
|
|
}
|
|
|
|
if (pWnd->pohBackBuffer)
|
|
{
|
|
#ifndef FORCE_SINGLE_BUF
|
|
pWnd->Base1.Color_Buffer_Y_Offset = pWnd->pohBackBuffer->aligned_y >> 5;
|
|
pWnd->Base0.Color_Buffer_X_Offset = pWnd->pohBackBuffer->aligned_x >> 6;
|
|
#endif // ndef FORCE_SINGLE_BUF
|
|
}
|
|
|
|
// FUTURE: MCDrvTrackWindow should set base ptrs via Host3DData port to keep sync
|
|
SETREG_NC( BASE0_ADDR_3D, pWnd->dwBase0 );
|
|
SETREG_NC( BASE1_ADDR_3D, pWnd->dwBase1 );
|
|
}
|
|
else
|
|
{
|
|
MCDBG_PRINT(" WOC_RGN_CLIENT: alloc of new resources FAILED");
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
ULONG MCDrvCreateMem(MCDSURFACE *pMCDSurface, MCDMEM *pMCDMem)
|
|
{
|
|
MCDBG_PRINT("MCDrvCreateMem");
|
|
return (ULONG)TRUE;
|
|
}
|
|
|
|
|
|
ULONG MCDrvDeleteMem(MCDMEM *pMCDMem, DHPDEV dhpdev)
|
|
{
|
|
MCDBG_PRINT("MCDrvDeleteMem");
|
|
return (ULONG)TRUE;
|
|
}
|
|
|
|
|
|
#define TIME_STAMP_TEXTURE(pRc,pTexCtlBlk) pTexCtlBlk->fLastDrvDraw=pRc->fNumDraws;
|
|
|
|
#define FAIL_ALL_DRAWING 0
|
|
#define FORCE_SYNC 0
|
|
|
|
|
|
BOOL __MCDTextureSetup(PDEV *ppdev, DEVRC *pRc)
|
|
{
|
|
MCDTEXTURESTATE *pTexState;
|
|
|
|
if (pRc->pLastTexture->dwTxCtlBits & CLMCD_TEX_BOGUS)
|
|
{
|
|
MCDBG_PRINT("Attempting to use bogus texture, ret false in __MCDTextureSetup");
|
|
return FALSE;
|
|
}
|
|
|
|
VERIFY_TEXTUREDATA_ACCESSIBLE(pRc->pLastTexture->pTex);
|
|
VERIFY_TEXTURELEVEL_ACCESSIBLE(pRc->pLastTexture->pTex);
|
|
|
|
pTexState= (MCDTEXTURESTATE *)&pRc->pLastTexture->pTex->pMCDTextureData->textureState;
|
|
|
|
MCDFREE_PRINT("internalFormat = %x", pRc->pLastTexture->pTex->pMCDTextureData->level->internalFormat);
|
|
|
|
if (((pTexState->minFilter == GL_NEAREST) ||
|
|
(pTexState->minFilter == GL_LINEAR)) &&
|
|
((pTexState->magFilter == GL_NEAREST) ||
|
|
(pTexState->magFilter == GL_LINEAR)))
|
|
{
|
|
// no filtering, or linear filtering, 5465 can do this...
|
|
}
|
|
else
|
|
{
|
|
// mipmapping - should punt on 5465
|
|
// However, some apps use mipmapping extensively (like GLQuake) and punting
|
|
// mipmapping makes them run very slow. Conformance test runs in a small
|
|
// window, so only punt if window small.
|
|
// Yes, this is a bit shady, but 5466 and following will have this fixed.
|
|
// Nobody will likely notice the problem until the 5466 is out
|
|
if ( (pRc->pMCDSurface->pWnd->clientRect.bottom -
|
|
pRc->pMCDSurface->pWnd->clientRect.top) < 110)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if ( pRc->Control0.Frame_Scaling_Enable &&
|
|
((pRc->MCDState.blendDst == GL_ONE_MINUS_SRC_COLOR) &&
|
|
!pRc->pLastTexture->bNegativeMap) ||
|
|
((pRc->MCDState.blendDst == GL_SRC_COLOR) &&
|
|
pRc->pLastTexture->bNegativeMap) )
|
|
{
|
|
// must invert the map
|
|
MCDFREE_PRINT("inverting map for framescaling");
|
|
pRc->pLastTexture->bNegativeMap = !pRc->pLastTexture->bNegativeMap;
|
|
|
|
if (pRc->pLastTexture->bNegativeMap &&
|
|
(pRc->pLastTexture->pTex->pMCDTextureData->level->internalFormat!=GL_LUMINANCE) &&
|
|
(pRc->pLastTexture->pTex->pMCDTextureData->level->internalFormat!=GL_LUMINANCE_ALPHA))
|
|
{
|
|
// FUTURE2: only LUMINANCE formats support inverted maps - should add all formats
|
|
MCDFREE_PRINT("MCDrvDraw: negative map not supported -punt");
|
|
// toggle back to original state - can use this texture when not frame scaling
|
|
pRc->pLastTexture->bNegativeMap = !pRc->pLastTexture->bNegativeMap;
|
|
return FALSE;
|
|
}
|
|
|
|
pRc->pLastTexture->pohTextureMap = NULL; // set to force reload
|
|
|
|
}
|
|
if (pRc->privateEnables & __MCDENABLE_TEXTUREMASKING)
|
|
{
|
|
#ifdef STRICT_CONFORMANCE
|
|
// should punt here, but GLQuake does this & nonpunt OK visually
|
|
if (!pRc->pLastTexture->bAlphaInTexture)
|
|
{
|
|
MCDFREE_PRINT("MCDrvDraw: alpha test, but no alpha in texture-punt");
|
|
return FALSE;
|
|
}
|
|
#endif // def STRICT_CONFORMANCE
|
|
|
|
// alphatest and frame scaling mutually exclusive
|
|
// (for now - may be some situtations where they're enabled together)
|
|
|
|
// masking only meaningful if texture has alpha
|
|
if (pRc->pLastTexture->bAlphaInTexture && !pRc->pLastTexture->bMasking )
|
|
{
|
|
MCDFREE_PRINT("reformat for Masking");
|
|
pRc->pLastTexture->bMasking = TRUE;
|
|
pRc->pLastTexture->pohTextureMap = NULL;// set to force reload
|
|
}
|
|
}
|
|
else if ( pRc->pLastTexture->bMasking )
|
|
{
|
|
// no alpha test, so reformat map if currently set for alpha test
|
|
MCDFREE_PRINT("reformat for NON-Masking");
|
|
pRc->pLastTexture->bMasking = FALSE;
|
|
pRc->pLastTexture->pohTextureMap = NULL; // set to force reload
|
|
}
|
|
|
|
// Null pohTexture means texture must be loaded before use
|
|
// also - must load before setting regs, since x/y loc determined
|
|
// by loader must be known before registers setup.
|
|
if (!pRc->pLastTexture->pohTextureMap)
|
|
{
|
|
// if load fails, punt
|
|
if (! __MCDLoadTexture(ppdev, pRc) )
|
|
{
|
|
MCDFREE_PRINT("MCDrvDraw: texture load failed-punt");
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// setup for new texture - punt if requirements beyond hw
|
|
if ( ! __MCDSetTextureRegisters(pRc) )
|
|
{
|
|
MCDFREE_PRINT("MCDrvDraw: texture regset failed-punt");
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
#if 1 // 0 here for NULL MCDrvDraw - for measuring "Upper limit" performance
|
|
|
|
ULONG MCDrvDraw(MCDSURFACE *pMCDSurface, MCDRC *pMCDRc, MCDMEM *prxExecMem,
|
|
UCHAR *pStart, UCHAR *pEnd)
|
|
{
|
|
MCDCOMMAND *pCmd = (MCDCOMMAND *)pStart;
|
|
MCDCOMMAND *pCmdNext;
|
|
DEVRC *pRc = (DEVRC *)pMCDRc->pvUser;
|
|
DEVWND *pDevWnd = (DEVWND *)(pMCDSurface->pWnd->pvUser);
|
|
PDEV *ppdev = (PDEV *)pMCDSurface->pso->dhpdev;
|
|
DWORD regtemp;
|
|
|
|
CHOP_ROUND_ON();
|
|
|
|
MCDBG_PRINT("MCDrvDraw");
|
|
|
|
#if TEST_3D_NO_DRAW
|
|
CHOP_ROUND_OFF();
|
|
return (ULONG)0;
|
|
#endif
|
|
|
|
// Make sure we have both a valid RC and window structure:
|
|
|
|
if (!pRc || !pDevWnd)
|
|
goto DrawExit;
|
|
|
|
pRc->ppdev = ppdev;
|
|
|
|
#if FAIL_ALL_DRAWING
|
|
goto DrawExit;
|
|
#endif
|
|
|
|
//
|
|
// If the resolution has changed and we have not yet updated our
|
|
// buffers, fail the call gracefully since the client won't be
|
|
// able to perform any software simulations at this point either.
|
|
// This applies to any of the other drawing functions as well (such
|
|
// as spans and clears).
|
|
//
|
|
|
|
if (pDevWnd->dispUnique != GetDisplayUniqueness(pRc->ppdev)) {
|
|
|
|
MCDBG_PRINT("MCDrvDraw: invalid (changed) resolution");
|
|
|
|
CHOP_ROUND_OFF();
|
|
return (ULONG)0;
|
|
}
|
|
|
|
if (pRc != (DEVRC *)ppdev->pLastDevRC) ContextSwitch(pRc);
|
|
|
|
if ((pRc->zBufEnabled && !pDevWnd->bValidZBuffer) ||
|
|
(pRc->backBufEnabled && !pDevWnd->bValidBackBuffer)) {
|
|
|
|
MCDBG_PRINT("MCDrvDraw has invalid buffers");
|
|
|
|
goto DrawExit;
|
|
}
|
|
|
|
if (pRc->pickNeeded) {
|
|
__MCDPickRenderingFuncs(pRc, pDevWnd);
|
|
__MCDPickClipFuncs(pRc);
|
|
pRc->pickNeeded = FALSE;
|
|
}
|
|
|
|
// If we're completely clipped, return success:
|
|
pRc->pEnumClip = pMCDSurface->pWnd->pClip;
|
|
|
|
if (!pRc->pEnumClip->c) {
|
|
|
|
CHOP_ROUND_OFF();
|
|
if (ppdev->LL_State.pDL->pdwNext != ppdev->LL_State.pDL->pdwStartOutPtr)
|
|
{
|
|
// Make sure all buffered data sent
|
|
//(__MCDPickRenderingFuncs may have buffered control reg writes)
|
|
_RunLaguna(ppdev,ppdev->LL_State.pDL->pdwNext);
|
|
}
|
|
|
|
return (ULONG)0;
|
|
}
|
|
|
|
// return here if we can't draw any primitives:
|
|
if (pRc->allPrimFail) {
|
|
goto DrawExit;
|
|
}
|
|
|
|
// Set these up in the device's RC so we can just pass a single pointer
|
|
// to do everything:
|
|
|
|
pRc->pMCDSurface = pMCDSurface;
|
|
pRc->pMCDRc = pMCDRc;
|
|
|
|
if ((pMCDSurface->pWnd->clientRect.left < 0) ||
|
|
(pMCDSurface->pWnd->clientRect.top < 0))
|
|
{
|
|
// primitive x or y might be negative - hw can't handle, so fail all
|
|
goto DrawExit;
|
|
}
|
|
else
|
|
{
|
|
int winrelative = FALSE;
|
|
|
|
pRc->xOffset = -pRc->viewportXAdjust;
|
|
pRc->yOffset = -pRc->viewportYAdjust;
|
|
|
|
// if draw to back buffer, and back buffer is window-sized (not full screen)
|
|
// then coordinates to hardware must be relative to window origin, not
|
|
// relative to screen. Clip rectangles given are always relative to screen origin,
|
|
// so may need to adjust.
|
|
if ((pRc->MCDState.drawBuffer == GL_BACK) &&
|
|
(pRc->ppdev->pohBackBuffer != pDevWnd->pohBackBuffer))
|
|
{
|
|
pRc->AdjClip.left = -pMCDSurface->pWnd->clientRect.left;
|
|
pRc->AdjClip.right = -pMCDSurface->pWnd->clientRect.left;
|
|
pRc->AdjClip.top = -pMCDSurface->pWnd->clientRect.top;
|
|
pRc->AdjClip.bottom= -pMCDSurface->pWnd->clientRect.top;
|
|
winrelative = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pRc->AdjClip.left = 0;
|
|
pRc->AdjClip.right = 0;
|
|
pRc->AdjClip.top = 0;
|
|
pRc->AdjClip.bottom= 0;
|
|
|
|
// coordinates to hardware will be screen relative, so add window offset
|
|
pRc->xOffset += pMCDSurface->pWnd->clientRect.left;
|
|
pRc->yOffset += pMCDSurface->pWnd->clientRect.top;
|
|
}
|
|
|
|
// floating pt versions
|
|
pRc->fxOffset = (float)((LONG)pRc->xOffset);
|
|
pRc->fyOffset = (float)((LONG)pRc->yOffset);
|
|
|
|
// Subtract of .5(almost) from y's before triangle
|
|
// setup make triangles match MSFT SW exactly.
|
|
// Can't just subtract .5 since coords could then be made
|
|
// negative - so add 1, the subtract .5. Starting
|
|
// Y in triangle setup code will have 1 subtracted to offset
|
|
pRc->fyOffset += (float)MCD_CONFORM_ADJUST - __MCD_ALMOST_HALF;
|
|
|
|
}
|
|
|
|
// increment the time stamp
|
|
pRc->fNumDraws+=(float)1.0;
|
|
|
|
pRc->pMemMin = pStart;
|
|
pRc->pvProvoking = (MCDVERTEX *)pStart; // bulletproofing
|
|
pRc->pMemMax = pEnd - sizeof(MCDVERTEX);
|
|
|
|
// warm up the hardware for drawing primitives:
|
|
HW_INIT_DRAWING_STATE(pMCDSurface, pMCDSurface->pWnd, pRc);
|
|
|
|
// If we have a single clipping rectangle, set it up in the hardware once
|
|
// for this batch:
|
|
|
|
if (pRc->pEnumClip->c == 1)
|
|
(*pRc->HWSetupClipRect)(pRc, &pRc->pEnumClip->arcl[0]);
|
|
|
|
// Now, loop through the commands and process the batch:
|
|
try {
|
|
|
|
if (!(pRc->privateEnables & (__MCDENABLE_PG_STIPPLE|__MCDENABLE_LINE_STIPPLE)))
|
|
{
|
|
// polygon stipple and line stipple both off
|
|
|
|
if ((ppdev->LL_State.pattern_ram_state != DITHER_LOADED) &&
|
|
(pRc->privateEnables & __MCDENABLE_DITHER))
|
|
{
|
|
DWORD *pdwNext = ppdev->LL_State.pDL->pdwNext;
|
|
int i;
|
|
|
|
*pdwNext++ = write_register( PATTERN_RAM_0_3D, 8 );
|
|
for( i=0; i<8; i++ )
|
|
*pdwNext++ = ppdev->LL_State.dither_array.pat[i];
|
|
|
|
ppdev->LL_State.pDL->pdwNext = pdwNext;
|
|
ppdev->LL_State.pattern_ram_state = DITHER_LOADED;
|
|
}
|
|
|
|
while (pCmd && (UCHAR *)pCmd < pEnd) {
|
|
|
|
volatile ULONG command = pCmd->command;
|
|
|
|
//MCDBG_PRINT("MCDrvDraw: command = %x ",command);
|
|
|
|
// Make sure we can read at least the command header:
|
|
|
|
if ((pEnd - (UCHAR *)pCmd) < sizeof(MCDCOMMAND))
|
|
goto DrawExit;
|
|
|
|
if (command <= GL_POLYGON) { // simple bounds check - GL_POLYGON is max command
|
|
|
|
if (pCmd->flags & MCDCOMMAND_RENDER_PRIMITIVE)
|
|
{
|
|
if (pRc->privateEnables & __MCDENABLE_TEXTURE)
|
|
{
|
|
if (pCmd->textureKey == TEXTURE_NOT_LOADED)
|
|
{
|
|
MCDBG_PRINT("MCDrvDraw: texturing, but texture not loaded - PUNT...");
|
|
MCDFREE_PRINT("MCDrvDraw: texturing, but texture not loaded - PUNT...");
|
|
goto DrawExit;
|
|
}
|
|
else
|
|
{
|
|
|
|
// if texture different than last time, or if texture not loaded
|
|
// (could have been updated since last MCDrvDraw which would have force it
|
|
// to be unloaded)
|
|
if ( (pRc->pLastTexture != (LL_Texture *)pCmd->textureKey) ||
|
|
!pRc->pLastTexture->pohTextureMap)
|
|
{
|
|
pRc->pLastTexture = (LL_Texture *)pCmd->textureKey;
|
|
TIME_STAMP_TEXTURE(pRc,pRc->pLastTexture); // time stamp before load
|
|
if (!__MCDTextureSetup(ppdev, pRc)) goto DrawExit;
|
|
}
|
|
else
|
|
{
|
|
TIME_STAMP_TEXTURE(pRc,pRc->pLastTexture);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
// MCDBG_PRINT("MCDrvDraw: non-stippled path... rendering....");
|
|
pCmdNext = (*pRc->primFunc[command])(pRc, pCmd);
|
|
}
|
|
else
|
|
{
|
|
// MCDBG_PRINT("MCDrvDraw: non-stippled path... not rendering....");
|
|
pCmdNext = pCmd->pNextCmd;
|
|
}
|
|
|
|
if (pCmdNext == pCmd)
|
|
{
|
|
MCDFREE_PRINT("MCDrvDraw: pCmdNext == pCmd-punt");
|
|
goto DrawExit; // primitive failed
|
|
}
|
|
if (!(pCmd = pCmdNext)) { // we're done with the batch
|
|
CHOP_ROUND_OFF();
|
|
|
|
if (ppdev->LL_State.pDL->pdwNext != ppdev->LL_State.pDL->pdwStartOutPtr)
|
|
{
|
|
// we should rarely get here - only for case of lots of
|
|
// consecutive stuffed culled or clipped causing no primitives to
|
|
// be sent to HW - in such case, setup info, clip, context
|
|
// switch etc. could stack up and overflow buffer unless
|
|
// we make sure all is dumped here...
|
|
// Recall primitive render procs will dump whole queue before they return
|
|
_RunLaguna(ppdev,ppdev->LL_State.pDL->pdwNext);
|
|
}
|
|
#if FORCE_SYNC
|
|
HW_WAIT_DRAWING_DONE(pRc);
|
|
#endif
|
|
return (ULONG)0;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
// polygon stipple AND/OR line stipple on - may need to reload pattern ram between primitives
|
|
while (pCmd && (UCHAR *)pCmd < pEnd) {
|
|
|
|
volatile ULONG command = pCmd->command;
|
|
|
|
//MCDBG_PRINT("MCDrvDraw: command = %x ",command);
|
|
|
|
// Make sure we can read at least the command header:
|
|
|
|
if ((pEnd - (UCHAR *)pCmd) < sizeof(MCDCOMMAND))
|
|
goto DrawExit;
|
|
|
|
if (command <= GL_POLYGON) { // simple bounds check - GL_POLYGON is max command
|
|
|
|
if (pCmd->flags & MCDCOMMAND_RENDER_PRIMITIVE)
|
|
{
|
|
// FUTURE: move all this pattern toggle to routine that is called indirectly
|
|
// FUTURE: with ptr to proc being reset by prior pattern ram load, etc.
|
|
LL_Pattern *Pattern=0;
|
|
int pat_inc = 1;
|
|
int pattern_bytes = 0;
|
|
|
|
if (command >= GL_TRIANGLES)
|
|
{
|
|
// area primitive - if stippled, may need to reload pattern
|
|
if (pRc->privateEnables & __MCDENABLE_PG_STIPPLE)
|
|
{
|
|
pattern_bytes = 8;
|
|
if (ppdev->LL_State.pattern_ram_state != AREA_PATTERN_LOADED)
|
|
{
|
|
ppdev->LL_State.pattern_ram_state = AREA_PATTERN_LOADED;
|
|
Pattern = &(pRc->fill_pattern);
|
|
// pat_inc remains 1;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// line primitive - if stippled, may need to reload pattern (OK for points though don't care)
|
|
if ( (pRc->privateEnables & __MCDENABLE_LINE_STIPPLE) &&
|
|
(command != GL_POINTS) )
|
|
{
|
|
// fill 8 word ram with same word so we get right pattern regardless
|
|
// of pattern_y_offset that may be set in base0 reg for proper pg stipple
|
|
pattern_bytes = 8;
|
|
if (ppdev->LL_State.pattern_ram_state != LINE_PATTERN_LOADED)
|
|
{
|
|
ppdev->LL_State.pattern_ram_state = LINE_PATTERN_LOADED;
|
|
Pattern = &(pRc->line_style);
|
|
pat_inc = 0; // don't increment through source pattern
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((ppdev->LL_State.pattern_ram_state != DITHER_LOADED) &&
|
|
!pattern_bytes && (pRc->privateEnables & __MCDENABLE_DITHER))
|
|
{
|
|
ppdev->LL_State.pattern_ram_state = DITHER_LOADED;
|
|
Pattern = &(ppdev->LL_State.dither_array);
|
|
pattern_bytes = 8;
|
|
// pat_inc remains 1;
|
|
}
|
|
|
|
if (Pattern)
|
|
{
|
|
DWORD *pdwNext = ppdev->LL_State.pDL->pdwNext;
|
|
int i;
|
|
|
|
*pdwNext++ = write_register( PATTERN_RAM_0_3D, pattern_bytes );
|
|
for( i=0; pattern_bytes>0; i+=pat_inc, pattern_bytes-- )
|
|
*pdwNext++ = Pattern->pat[ i ];
|
|
|
|
// leave data queued for now, primitive render procs will send
|
|
ppdev->LL_State.pDL->pdwNext = pdwNext;
|
|
}
|
|
|
|
if (pRc->privateEnables & __MCDENABLE_TEXTURE)
|
|
{
|
|
if (pCmd->textureKey == TEXTURE_NOT_LOADED)
|
|
{
|
|
MCDBG_PRINT("MCDrvDraw: texturing, but texture not loaded - PUNT...");
|
|
goto DrawExit;
|
|
}
|
|
else
|
|
{
|
|
// if texture different than last time, or if texture not loaded
|
|
// (could have been updated since last MCDrvDraw which would have force it
|
|
// to be unloaded)
|
|
if ( (pRc->pLastTexture != (LL_Texture *)pCmd->textureKey) ||
|
|
!pRc->pLastTexture->pohTextureMap)
|
|
{
|
|
pRc->pLastTexture = (LL_Texture *)pCmd->textureKey;
|
|
TIME_STAMP_TEXTURE(pRc,pRc->pLastTexture); // time stamp before load
|
|
if (!__MCDTextureSetup(ppdev, pRc)) goto DrawExit;
|
|
}
|
|
else
|
|
{
|
|
TIME_STAMP_TEXTURE(pRc,pRc->pLastTexture);
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|
|
// MCDBG_PRINT("MCDrvDraw: stippled path... rendering....");
|
|
pCmdNext = (*pRc->primFunc[command])(pRc, pCmd);
|
|
}
|
|
else
|
|
{
|
|
// MCDBG_PRINT("MCDrvDraw: stippled path... not rendering....");
|
|
pCmdNext = pCmd->pNextCmd;
|
|
}
|
|
|
|
if (pCmdNext == pCmd)
|
|
goto DrawExit; // primitive failed
|
|
if (!(pCmd = pCmdNext)) { // we're done with the batch
|
|
CHOP_ROUND_OFF();
|
|
|
|
if (ppdev->LL_State.pDL->pdwNext != ppdev->LL_State.pDL->pdwStartOutPtr)
|
|
{
|
|
// we should rarely get here - only for case of lots of
|
|
// consecutive stuffed culled or clipped causing no primitives to
|
|
// be sent to HW - in such case, setup info, clip, context
|
|
// switch etc. could stack up and overflow buffer unless
|
|
// we make sure all is dumped here...
|
|
// Recall primitive render procs will dump whole queue before they return
|
|
_RunLaguna(ppdev,ppdev->LL_State.pDL->pdwNext);
|
|
}
|
|
|
|
#if FORCE_SYNC
|
|
HW_WAIT_DRAWING_DONE(pRc);
|
|
#endif
|
|
return (ULONG)0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
MCDBG_PRINT("!!Exception in MCDrvDraw!!");
|
|
|
|
// will fall through to DrawExit condition below...
|
|
}
|
|
|
|
// ERROR (or Punt) CONDITION
|
|
DrawExit:
|
|
|
|
MCDFREE_PRINT("*****************************************************");
|
|
MCDFREE_PRINT("************* PUNTING in MCDrvDraw ******************");
|
|
MCDFREE_PRINT("*****************************************************");
|
|
|
|
if (ppdev->LL_State.pDL->pdwNext != ppdev->LL_State.pDL->pdwStartOutPtr)
|
|
{
|
|
// we should rarely get here - only for case of lots of
|
|
// consecutive stuff culls or clips causing no primitives to
|
|
// be sent to HW - in such case, setup info, clip, context
|
|
// switch etc. could stack up and overflow buffer unless
|
|
// we make sure all is dumped here...
|
|
_RunLaguna(ppdev,ppdev->LL_State.pDL->pdwNext);
|
|
}
|
|
|
|
// restore the hardware state:
|
|
CHOP_ROUND_OFF();
|
|
HW_WAIT_DRAWING_DONE(pRc);
|
|
|
|
return (ULONG)pCmd; // some sort of overrun has occurred
|
|
}
|
|
|
|
#else // NULL MCDrvDraw
|
|
|
|
ULONG MCDrvDraw(MCDSURFACE *pMCDSurface, MCDRC *pMCDRc, MCDMEM *prxExecMem,
|
|
UCHAR *pStart, UCHAR *pEnd)
|
|
{
|
|
MCDCOMMAND *pCmd = (MCDCOMMAND *)pStart;
|
|
MCDCOMMAND *pCmdNext;
|
|
|
|
try {
|
|
// Now, loop through the commands and process the batch:
|
|
while (pCmd && (UCHAR *)pCmd < pEnd) {
|
|
|
|
pCmdNext = pCmd->pNextCmd;
|
|
|
|
if (!(pCmd = pCmdNext)) { // we're done with the batch
|
|
return (ULONG)0;
|
|
}
|
|
}
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
MCDBG_PRINT("!!Exception in NULL Version of MCDrvDraw!!");
|
|
|
|
}
|
|
|
|
return (ULONG)pCmd; // some sort of overrun has occurred
|
|
}
|
|
|
|
#endif // NULL MCDrvDraw
|
|
|
|
ULONG MCDrvClear(MCDSURFACE *pMCDSurface, MCDRC *pMCDRc, ULONG buffers)
|
|
{
|
|
DEVRC *pRc = (DEVRC *)pMCDRc->pvUser;
|
|
MCDWINDOW *pWnd;
|
|
ULONG cClip;
|
|
RECTL *pClip;
|
|
|
|
MCDBG_PRINT("MCDrvClear");
|
|
|
|
MCD_CHECK_RC(pRc);
|
|
|
|
pWnd = pMCDSurface->pWnd;
|
|
|
|
MCD_CHECK_BUFFERS_VALID(pMCDSurface, pRc, TRUE);
|
|
|
|
pRc->ppdev = (PDEV *)pMCDSurface->pso->dhpdev;
|
|
|
|
#if FAIL_ALL_DRAWING
|
|
return TRUE;
|
|
#endif
|
|
|
|
if (buffers & ~(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |
|
|
GL_ACCUM_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) {
|
|
MCDBG_PRINT("MCDrvClear: attempted to clear buffer of unknown type");
|
|
return FALSE;
|
|
}
|
|
|
|
if ((buffers & GL_DEPTH_BUFFER_BIT) && (!pRc->zBufEnabled))
|
|
{
|
|
MCDBG_PRINT("MCDrvClear: clear z requested with z-buffer disabled.");
|
|
HW_WAIT_DRAWING_DONE(pRc);
|
|
return FALSE;
|
|
}
|
|
|
|
if (buffers & (GL_ACCUM_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) {
|
|
MCDBG_PRINT("MCDrvClear: attempted to clear accum or stencil buffer");
|
|
return FALSE;
|
|
}
|
|
|
|
// Return if we have nothing to clear:
|
|
if (!(cClip = pWnd->pClip->c))
|
|
return TRUE;
|
|
|
|
// We have to protect against bad clear colors since this can
|
|
// potentially cause an FP exception:
|
|
try {
|
|
for (pClip = &pWnd->pClip->arcl[0]; cClip; cClip--,
|
|
pClip++)
|
|
{
|
|
// Do the fill:
|
|
|
|
HW_FILL_RECT(pMCDSurface, pRc, pClip, buffers);
|
|
}
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
MCDBG_PRINT("!!Exception in MCDrvClear!!");
|
|
return FALSE;
|
|
}
|
|
|
|
#if FORCE_SYNC
|
|
HW_WAIT_DRAWING_DONE(pRc);
|
|
#endif
|
|
|
|
return (ULONG)TRUE;
|
|
}
|
|
|
|
|
|
ULONG MCDrvSpan(MCDSURFACE *pMCDSurface, MCDRC *pMCDRc, MCDMEM *pMCDMem,
|
|
MCDSPAN *pMCDSpan, BOOL bRead)
|
|
{
|
|
DEVRC *pRc = (DEVRC *)pMCDRc->pvUser;
|
|
PDEV *ppdev = (PDEV *)pMCDSurface->pso->dhpdev;
|
|
UCHAR *pScreen;
|
|
UCHAR *pPixels;
|
|
MCDWINDOW *pWnd;
|
|
DEVWND *pDevWnd;
|
|
LONG xLeftOrg, xLeft, xRight, y;
|
|
LONG bufferYBias;
|
|
ULONG bytesNeeded;
|
|
ULONG cjHwPel;
|
|
int winoffset = FALSE;
|
|
|
|
MCD_CHECK_RC(pRc);
|
|
|
|
pWnd = pMCDSurface->pWnd;
|
|
|
|
// Return if we have nothing to clip:
|
|
|
|
if (!pWnd->pClip->c)
|
|
return TRUE;
|
|
|
|
// Fail if number of pixels is negative:
|
|
|
|
if (pMCDSpan->numPixels < 0) {
|
|
MCDBG_PRINT("MCDrvSpan: numPixels < 0");
|
|
return FALSE;
|
|
}
|
|
|
|
MCD_CHECK_BUFFERS_VALID(pMCDSurface, pRc, TRUE);
|
|
|
|
pDevWnd = (DEVWND *)pWnd->pvUser;
|
|
|
|
xLeft = xLeftOrg = (pMCDSpan->x + pWnd->clientRect.left);
|
|
xRight = (xLeft + pMCDSpan->numPixels);
|
|
y = pMCDSpan->y + pWnd->clientRect.top;
|
|
|
|
// Early-out spans which are not visible:
|
|
|
|
if ((y < pWnd->clipBoundsRect.top) ||
|
|
(y >= pWnd->clipBoundsRect.bottom))
|
|
return TRUE;
|
|
|
|
xLeft = max(xLeft, pWnd->clipBoundsRect.left);
|
|
xRight = min(xRight, pWnd->clipBoundsRect.right);
|
|
|
|
// Return if empty:
|
|
|
|
if (xLeft >= xRight)
|
|
return TRUE;
|
|
|
|
cjHwPel = ppdev->iBytesPerPixel;
|
|
|
|
pScreen = ppdev->pjScreen;
|
|
|
|
switch (pMCDSpan->type) {
|
|
case MCDSPAN_FRONT:
|
|
// pScreen remains the same
|
|
break;
|
|
|
|
case MCDSPAN_BACK:
|
|
pScreen += pDevWnd->backBufferOffset;
|
|
if (ppdev->pohBackBuffer != pDevWnd->pohBackBuffer) winoffset = TRUE;
|
|
break;
|
|
|
|
case MCDSPAN_DEPTH:
|
|
cjHwPel = 2;
|
|
pScreen += pDevWnd->zBufferOffset;
|
|
if (ppdev->pohZBuffer != pDevWnd->pohZBuffer) winoffset = TRUE;
|
|
break;
|
|
|
|
default:
|
|
MCDBG_PRINT("MCDrvReadSpan: Unrecognized buffer %d", pMCDSpan->type);
|
|
return FALSE;
|
|
}
|
|
|
|
if (winoffset)
|
|
{
|
|
// offset from window origin, remove client rectangle offsets applied above
|
|
y -= pWnd->clientRect.top;
|
|
xLeft -= pWnd->clientRect.left;
|
|
xLeftOrg -= pWnd->clientRect.left;
|
|
xRight-= pWnd->clientRect.left;
|
|
}
|
|
|
|
// add offset to top of framebuffer, and offset within selected buffer
|
|
pScreen += (y * ppdev->lDeltaScreen) + (xLeft * cjHwPel);
|
|
|
|
bytesNeeded = pMCDSpan->numPixels * cjHwPel;
|
|
|
|
// Make sure we don't read past the end of the buffer:
|
|
|
|
if (((char *)pMCDSpan->pPixels + bytesNeeded) >
|
|
((char *)pMCDMem->pMemBase + pMCDMem->memSize)) {
|
|
MCDBG_PRINT("MCDrvSpan: Buffer too small");
|
|
return FALSE;
|
|
}
|
|
|
|
WAIT_HW_IDLE(ppdev);
|
|
|
|
pPixels = pMCDSpan->pPixels;
|
|
|
|
//MCDBG_PRINT("MCDrvSpan: read %d, (%d, %d) type %d *ppix=%x, bytes=%d", bRead, pMCDSpan->x, pMCDSpan->y, pMCDSpan->type, *pPixels, bytesNeeded);
|
|
|
|
if (bRead) {
|
|
|
|
if (xLeftOrg != xLeft) // compensate for clip rectangle
|
|
pPixels = (UCHAR *)pMCDSpan->pPixels + ((xLeft - xLeftOrg) * cjHwPel);
|
|
|
|
RtlCopyMemory(pPixels, pScreen, (xRight - xLeft) * cjHwPel);
|
|
|
|
} else {
|
|
LONG xLeftClip, xRightClip, yClip;
|
|
RECTL *pClip;
|
|
RECTL AdjClip;
|
|
ULONG cClip;
|
|
|
|
for (pClip = &pWnd->pClip->arcl[0], cClip = pWnd->pClip->c; cClip;
|
|
cClip--, pClip++)
|
|
{
|
|
UCHAR *pScreenClip;
|
|
|
|
if (winoffset)
|
|
{
|
|
AdjClip.left = pClip->left - pWnd->clientRect.left;
|
|
AdjClip.right = pClip->right - pWnd->clientRect.left;
|
|
AdjClip.top = pClip->top - pWnd->clientRect.top;
|
|
AdjClip.bottom = pClip->bottom - pWnd->clientRect.top;
|
|
}
|
|
else
|
|
{
|
|
AdjClip.left = pClip->left;
|
|
AdjClip.right = pClip->right;
|
|
AdjClip.top = pClip->top;
|
|
AdjClip.bottom = pClip->bottom;
|
|
}
|
|
|
|
// Test for trivial cases:
|
|
|
|
if (y < AdjClip.top)
|
|
break;
|
|
|
|
// Determine trivial rejection for just this span
|
|
|
|
if ((xLeft >= AdjClip.right) ||
|
|
(y >= AdjClip.bottom) ||
|
|
(xRight <= AdjClip.left))
|
|
continue;
|
|
|
|
// Intersect current clip rect with the span:
|
|
|
|
xLeftClip = max(xLeft, AdjClip.left);
|
|
xRightClip = min(xRight, AdjClip.right);
|
|
|
|
if (xLeftClip >= xRightClip)
|
|
continue;
|
|
|
|
if (xLeftOrg != xLeftClip)
|
|
pPixels = (UCHAR *)pMCDSpan->pPixels +
|
|
((xLeftClip - xLeftOrg) * cjHwPel);
|
|
|
|
pScreenClip = pScreen + ((xLeftClip - xLeft) * cjHwPel);
|
|
|
|
// Write the span:
|
|
RtlCopyMemory(pScreenClip, pPixels, (xRightClip - xLeftClip) * cjHwPel);
|
|
}
|
|
}
|
|
|
|
return (ULONG)TRUE;
|
|
}
|
|
|
|
|
|
ULONG MCDrvSync (MCDSURFACE *pMCDSurface, MCDRC *pRc)
|
|
{
|
|
PDEV *ppdev = (PDEV *)pMCDSurface->pso->dhpdev;
|
|
MCDBG_PRINT( "MCDrvSync\n");
|
|
|
|
WAIT_HW_IDLE(ppdev);
|
|
|
|
return FALSE;
|
|
}
|
|
ULONG /* FASTCALL */ MCDrvDummyDrvDrawPixels (MCDSURFACE *pMcdSurface, MCDRC *pRc,
|
|
ULONG width, ULONG height, ULONG format,
|
|
ULONG type, VOID *pPixels, BOOL packed)
|
|
{
|
|
MCDBG_PRINT( "MCDrvDummyDrvDrawPixels\n");
|
|
return FALSE;
|
|
}
|
|
ULONG /* FASTCALL */ MCDrvDummyDrvReadPixels (MCDSURFACE *pMcdSurface, MCDRC *pRc,
|
|
LONG x, LONG y, ULONG width, ULONG height, ULONG format,
|
|
ULONG type, VOID *pPixels)
|
|
{
|
|
MCDBG_PRINT( "MCDrvDummyDrvReadPixels\n");
|
|
return FALSE;
|
|
}
|
|
ULONG /* FASTCALL */ MCDrvDummyDrvCopyPixels (MCDSURFACE *pMcdSurface, MCDRC *pRc,
|
|
LONG x, LONG y, ULONG width, ULONG height, ULONG type)
|
|
{
|
|
MCDBG_PRINT( "MCDrvDummyDrvCopyPixels\n");
|
|
return FALSE;
|
|
}
|
|
ULONG /* FASTCALL */ MCDrvDummyDrvPixelMap (MCDSURFACE *pMcdSurface, MCDRC *pRc,
|
|
ULONG mapType, ULONG mapSize, VOID *pMap)
|
|
{
|
|
MCDBG_PRINT( "MCDrvDummyDrvPixelMap\n");
|
|
return FALSE;
|
|
}
|
|
|
|
#define RECORD_TEXTURE_STATE(pTexCtlBlk,pTexState) \
|
|
{ \
|
|
pTexCtlBlk->dwTxCtlBits |= (pTexState->sWrapMode==GL_CLAMP) ? CLMCD_TEX_U_SATURATE : 0; \
|
|
pTexCtlBlk->dwTxCtlBits |= (pTexState->tWrapMode==GL_CLAMP) ? CLMCD_TEX_V_SATURATE : 0; \
|
|
/* caller verifies we're not mipmapping and sets up to punt if we are*/ \
|
|
/* MCD_NOTE: only 1 filter on Laguna, not min/mag, so set filter on if either on */ \
|
|
/* MCD_NOTE: may need to punt in case min!=mag for 100% compliance */ \
|
|
/* MCD_NOTE: MSFT said using LINEAR for both OK if 1 LINEAR, 1 NEAREST */ \
|
|
pTexCtlBlk->dwTxCtlBits |= (pTexState->minFilter==GL_LINEAR) ? CLMCD_TEX_FILTER : 0; \
|
|
pTexCtlBlk->dwTxCtlBits |= (pTexState->magFilter==GL_LINEAR) ? CLMCD_TEX_FILTER : 0; \
|
|
}
|
|
|
|
|
|
ULONG MCDrvCreateTexture(MCDSURFACE *pMCDSurface, MCDRC *pMCDRc, MCDTEXTURE *pTex)
|
|
{
|
|
PDEV *ppdev = (PDEV *)pMCDSurface->pso->dhpdev;
|
|
DEVRC *pRc = (DEVRC *)pMCDRc->pvUser;
|
|
MCDMIPMAPLEVEL *level;
|
|
MCDTEXTURESTATE *pTexState;
|
|
LL_Texture *pTexCtlBlk;
|
|
SIZEL mapsize;
|
|
|
|
MCDFREE_PRINT("MCDrvCreateTexture");
|
|
|
|
// initialize to FAIL condition
|
|
pTex->textureKey = TEXTURE_NOT_LOADED;
|
|
|
|
VERIFY_TEXTUREDATA_ACCESSIBLE(pTex);
|
|
|
|
pTexState= (MCDTEXTURESTATE *)&pTex->pMCDTextureData->textureState;
|
|
|
|
VERIFY_TEXTURELEVEL_ACCESSIBLE(pTex);
|
|
|
|
level = pTex->pMCDTextureData->level;
|
|
|
|
if ((level[0].width != 0) && (level[0].height != 0) &&
|
|
(level[0].border == 0) && // punt if bordered
|
|
(level[0].widthImage <= 512) && (level[0].heightImage <= 512)) // punt if too big
|
|
{
|
|
MCDBG_PRINT_TEX("width, height = %ld %ld", level[0].width, level[0].height);
|
|
MCDBG_PRINT_TEX("internalFormat = 0x%08lx", level[0].internalFormat );
|
|
MCDBG_PRINT_TEX("\t%s",
|
|
(level[0].internalFormat == GL_ALPHA ) ? "GL_ALPHA " :
|
|
(level[0].internalFormat == GL_RGB ) ? "GL_RGB " :
|
|
(level[0].internalFormat == GL_RGBA ) ? "GL_RGBA " :
|
|
(level[0].internalFormat == GL_LUMINANCE ) ? "GL_LUMINANCE " :
|
|
(level[0].internalFormat == GL_LUMINANCE_ALPHA ) ? "GL_LUMINANCE_ALPHA " :
|
|
(level[0].internalFormat == GL_INTENSITY ) ? "GL_INTENSITY " :
|
|
(level[0].internalFormat == GL_BGR_EXT ) ? "GL_BGR_EXT " :
|
|
(level[0].internalFormat == GL_BGRA_EXT ) ? "GL_BGRA_EXT " :
|
|
(level[0].internalFormat == GL_COLOR_INDEX8_EXT ) ? "GL_COLOR_INDEX8_EXT " :
|
|
(level[0].internalFormat == GL_COLOR_INDEX16_EXT) ? "GL_COLOR_INDEX16_EXT" :
|
|
"unknown");
|
|
|
|
if ( !(pTexCtlBlk = (LL_Texture *)MCDAlloc(sizeof(LL_Texture))) )
|
|
{
|
|
MCDBG_PRINT(" create texture failed -> MCDAlloc of LL_Texture failed ");
|
|
return FALSE;
|
|
}
|
|
|
|
// add new texture control block to global list (visible to all contexts)
|
|
ppdev->pLastTexture->next = pTexCtlBlk;
|
|
pTexCtlBlk->prev = ppdev->pLastTexture;
|
|
pTexCtlBlk->next = NULL;
|
|
ppdev->pLastTexture = pTexCtlBlk;
|
|
|
|
pTexCtlBlk->pohTextureMap = NULL; // texture not loaded yet
|
|
pTexCtlBlk->bNegativeMap = FALSE; // set TRUE to load 1-R,1-G,1-B
|
|
pTexCtlBlk->bMasking = FALSE; // set TRUE to load in 1555 or 1888 mode for alphatest (masking)
|
|
pTexCtlBlk->pTex = pTex; // ptr to user's texture description
|
|
|
|
// give new texture highest priority
|
|
TIME_STAMP_TEXTURE(pRc,pTexCtlBlk);
|
|
|
|
// scale by priority - 1.0 is max, 0.0 is min
|
|
pTexCtlBlk->fLastDrvDraw *= pTex->pMCDTextureData->textureObjState.priority;
|
|
|
|
// set key MCD will use in MCDrvDraw to select this texture
|
|
pTex->textureKey = (ULONG)pTexCtlBlk;
|
|
pTexCtlBlk->dwTxCtlBits = 0;
|
|
RECORD_TEXTURE_STATE(pTexCtlBlk,pTexState)
|
|
|
|
// Store the texture properties in the fields
|
|
//
|
|
pTexCtlBlk->fWidth = (float)level[0].widthImage;
|
|
pTexCtlBlk->fHeight = (float)level[0].heightImage;
|
|
//pTexCtlBlk->bLookupOffset = 0;
|
|
|
|
// if texture has alpha, it needs to be used in alpha equation, as well as
|
|
// in generation of original source color - so really 2 levels of alpha equations
|
|
// HW only has 1 level, so must punt if blending on
|
|
if ( (level[0].internalFormat == GL_BGRA_EXT) ||
|
|
(level[0].internalFormat == GL_RGBA) ||
|
|
(level[0].internalFormat == GL_ALPHA) ||
|
|
(level[0].internalFormat == GL_INTENSITY) ||
|
|
(level[0].internalFormat == GL_LUMINANCE_ALPHA) )
|
|
pTexCtlBlk->bAlphaInTexture = TRUE;
|
|
else
|
|
pTexCtlBlk->bAlphaInTexture = FALSE;
|
|
|
|
if (level[0].widthImage >= 16)
|
|
{
|
|
pTexCtlBlk->bSizeMask = level[0].widthLog2-4; // convert 16->0, 32->1, etc...
|
|
mapsize.cx = level[0].widthImage;
|
|
}
|
|
else
|
|
{
|
|
// width < 16 - set it to 16 anyway, will stretch to 16 at end of this routine
|
|
pTexCtlBlk->bSizeMask = 0;
|
|
mapsize.cx = 16;
|
|
pTexCtlBlk->fWidth = (float)16.0;
|
|
}
|
|
|
|
if (level[0].heightImage >= 16)
|
|
{
|
|
pTexCtlBlk->bSizeMask |= (level[0].heightLog2-4)<<4; // convert 16->0, 32->1, etc...
|
|
mapsize.cy = level[0].heightImage;
|
|
}
|
|
else
|
|
{
|
|
// height < 16 - set it to 16 anyway, will stretch to 16 at end of this routine
|
|
// pTexCtlBlk->bSizeMask remains the same
|
|
mapsize.cy = 16;
|
|
pTexCtlBlk->fHeight = (float)16.0;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
MCDBG_PRINT_TEX(" create texture failed -> some parm beyond hw caps, no attempt to alloc ");
|
|
MCDBG_PRINT_TEX(" width, height = %ld %ld", level[0].width, level[0].height);
|
|
MCDBG_PRINT_TEX(" border = %ld", level[0].border );
|
|
MCDBG_PRINT_TEX(" WILL ALLOC CTL BLOCK AND TAG AS BOGUS");
|
|
|
|
// allocate control block, but tag as bogus to force all MCDrvDraw's with this
|
|
// texture to punt.
|
|
// Apparently, failing CreateTexture can lead to a bug in MCD above the driver.
|
|
// It looks like when CreateTexture fails, MCD may send a key for a texture
|
|
// that was earlier deleted.
|
|
// Will fix this by never failing CreateTexture, but setting bogus condition
|
|
// so that we never render with it.
|
|
|
|
if ( !(pTexCtlBlk = (LL_Texture *)MCDAlloc(sizeof(LL_Texture))) )
|
|
{
|
|
MCDBG_PRINT(" create texture failed -> MCDAlloc of LL_Texture failed ");
|
|
return FALSE;
|
|
}
|
|
|
|
// add new texture control block to global list (visible to all contexts)
|
|
ppdev->pLastTexture->next = pTexCtlBlk;
|
|
pTexCtlBlk->prev = ppdev->pLastTexture;
|
|
pTexCtlBlk->next = NULL;
|
|
ppdev->pLastTexture = pTexCtlBlk;
|
|
|
|
pTexCtlBlk->dwTxCtlBits = CLMCD_TEX_BOGUS;
|
|
|
|
pTexCtlBlk->pohTextureMap = NULL; // texture not loaded yet
|
|
pTexCtlBlk->pTex = pTex; // ptr to user's texture description
|
|
|
|
// set key MCD will use in MCDrvDraw to select this texture
|
|
pTex->textureKey = (ULONG)pTexCtlBlk;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
ULONG MCDrvUpdateSubTexture(MCDSURFACE *pMCDSurface, MCDRC *pRc,
|
|
MCDTEXTURE *pTex, ULONG lod, RECTL *pRect)
|
|
{
|
|
PDEV *ppdev = (PDEV *)pMCDSurface->pso->dhpdev;
|
|
LL_Texture *pTexCtlBlk;
|
|
|
|
MCDBG_PRINT_TEX("MCDrvUpdateSubTexture");
|
|
|
|
CHK_TEX_KEY(pTex);
|
|
|
|
// simply free texture map - will force it to be reloaded before next use
|
|
//
|
|
if (pTex->textureKey != TEXTURE_NOT_LOADED)
|
|
{
|
|
pTexCtlBlk = (LL_Texture *)pTex->textureKey;
|
|
|
|
// free off screen memory allocated for texture, if texture currently loaded
|
|
if (pTexCtlBlk->pohTextureMap)
|
|
{
|
|
ppdev->pFreeOffScnMem(ppdev, pTexCtlBlk->pohTextureMap);
|
|
pTexCtlBlk->pohTextureMap = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
ULONG MCDrvUpdateTexturePalette(MCDSURFACE *pMCDSurface, MCDRC *pRc,
|
|
MCDTEXTURE *pTex, ULONG start,
|
|
ULONG numEntries)
|
|
{
|
|
PDEV *ppdev = (PDEV *)pMCDSurface->pso->dhpdev;
|
|
LL_Texture *pTexCtlBlk;
|
|
|
|
MCDBG_PRINT_TEX("MCDrvUpdateTexturePalette");
|
|
|
|
CHK_TEX_KEY(pTex);
|
|
|
|
VERIFY_TEXTUREDATA_ACCESSIBLE(pTex);
|
|
VERIFY_TEXTURELEVEL_ACCESSIBLE(pTex);
|
|
|
|
// make sure palette will be used before we trouble ourselves to take action
|
|
if ((pTex->pMCDTextureData->level->internalFormat==GL_COLOR_INDEX8_EXT) ||
|
|
(pTex->pMCDTextureData->level->internalFormat==GL_COLOR_INDEX16_EXT))
|
|
{
|
|
// simply free texture map - will force it to be reloaded before next use
|
|
// when reloaded, new palette will be used
|
|
if (pTex->textureKey != TEXTURE_NOT_LOADED)
|
|
{
|
|
pTexCtlBlk = (LL_Texture *)pTex->textureKey;
|
|
|
|
// free off screen memory allocated for texture, if texture currently loaded
|
|
if (pTexCtlBlk->pohTextureMap)
|
|
{
|
|
ppdev->pFreeOffScnMem(ppdev, pTexCtlBlk->pohTextureMap);
|
|
pTexCtlBlk->pohTextureMap = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
ULONG MCDrvUpdateTexturePriority(MCDSURFACE *pMCDSurface, MCDRC *pMCDRc,
|
|
MCDTEXTURE *pTex)
|
|
{
|
|
LL_Texture *pTexCtlBlk;
|
|
DEVRC *pRc = pMCDRc->pvUser;
|
|
|
|
MCDBG_PRINT_TEX("MCDrvUpdateTexturePriority");
|
|
|
|
CHK_TEX_KEY(pTex);
|
|
|
|
VERIFY_TEXTUREDATA_ACCESSIBLE(pTex);
|
|
|
|
pTexCtlBlk = (LL_Texture *)pTex->textureKey;
|
|
|
|
// give new texture highest priority...
|
|
TIME_STAMP_TEXTURE(pRc,pTexCtlBlk);
|
|
|
|
// ....then scale by new priority - 1.0 is max, 0.0 is min
|
|
pTexCtlBlk->fLastDrvDraw *= pTex->pMCDTextureData->textureObjState.priority;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
ULONG MCDrvUpdateTextureState(MCDSURFACE *pMCDSurface, MCDRC *pMCDRc,
|
|
MCDTEXTURE *pTex)
|
|
{
|
|
DEVRC *pRc = (DEVRC *)pMCDRc->pvUser;
|
|
LL_Texture *pTexCtlBlk;
|
|
MCDTEXTURESTATE *pTexState;
|
|
|
|
MCDBG_PRINT_TEX("MCDrvUpdateTextureState");
|
|
|
|
CHK_TEX_KEY(pTex);
|
|
|
|
VERIFY_TEXTUREDATA_ACCESSIBLE(pTex);
|
|
|
|
pTexCtlBlk = (LL_Texture *)pTex->textureKey;
|
|
|
|
pTexState = (MCDTEXTURESTATE *)&pTex->pMCDTextureData->textureState;
|
|
|
|
// turn off all control bits - while preserving the "bogus" indicator
|
|
pTexCtlBlk->dwTxCtlBits &= CLMCD_TEX_BOGUS;
|
|
|
|
RECORD_TEXTURE_STATE(pTexCtlBlk,pTexState)
|
|
|
|
// if last texture was this one, reset so next use will force regs to be reloaded
|
|
if ( pRc->pLastTexture==pTexCtlBlk ) pRc->pLastTexture=NULL;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
ULONG MCDrvTextureStatus(MCDSURFACE *pMCDSurface, MCDRC *pRc,
|
|
MCDTEXTURE *pTex)
|
|
{
|
|
MCDBG_PRINT_TEX("MCDrvTextureStatus");
|
|
|
|
CHK_TEX_KEY(pTex);
|
|
|
|
if (pTex->textureKey == TEXTURE_NOT_LOADED)
|
|
{
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
return MCDRV_TEXTURE_RESIDENT;
|
|
}
|
|
|
|
}
|
|
|
|
ULONG MCDrvDeleteTexture(MCDTEXTURE *pTex, DHPDEV dhpdev)
|
|
{
|
|
PDEV *ppdev = (PDEV *)dhpdev;
|
|
LL_Texture *pTexCtlBlk;
|
|
|
|
MCDBG_PRINT_TEX("MCDrvDeleteTexture");
|
|
|
|
CHK_TEX_KEY(pTex);
|
|
|
|
MCDBG_PRINT(" key = %x " , pTex->textureKey);
|
|
|
|
if (pTex->textureKey != TEXTURE_NOT_LOADED)
|
|
{
|
|
pTexCtlBlk = (LL_Texture *)pTex->textureKey;
|
|
|
|
// free off screen memory allocated for texture, if texture currently loaded
|
|
if (pTexCtlBlk->pohTextureMap)
|
|
{
|
|
MCDFREE_PRINT(" MCDrvDeleteTexture, FREEING....size = %x by %x",
|
|
(LONG)pTexCtlBlk->fHeight,
|
|
(LONG)pTexCtlBlk->fWidth);
|
|
ppdev->pFreeOffScnMem(ppdev, pTexCtlBlk->pohTextureMap);
|
|
pTexCtlBlk->pohTextureMap = NULL;
|
|
}
|
|
|
|
// Remove from global list of texture control blocks...
|
|
//
|
|
// if there's not a next link, this is last one
|
|
if ( !pTexCtlBlk->next )
|
|
{
|
|
// this was last block, so now "prev" is last block
|
|
ppdev->pLastTexture = pTexCtlBlk->prev;
|
|
pTexCtlBlk->prev->next = NULL;
|
|
}
|
|
else
|
|
{
|
|
// there will always be a prev link for this block, and we now know
|
|
// there is a next block, so make "prev's" next point to what was
|
|
// this block's next;
|
|
pTexCtlBlk->prev->next = pTexCtlBlk->next;
|
|
|
|
// "next's" prev ptr pointed to this block, which is going away
|
|
// so make it point to this block's prev
|
|
pTexCtlBlk->next->prev = pTexCtlBlk->prev;
|
|
}
|
|
|
|
// set "bogus" bit before freeing, in case MCD tries to use key after delete
|
|
pTexCtlBlk->dwTxCtlBits = CLMCD_TEX_BOGUS;
|
|
|
|
// now discard the block
|
|
MCDFree((UCHAR *)pTexCtlBlk);
|
|
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
BOOL MCDrvGetEntryPoints(MCDSURFACE *pMCDSurface, MCDDRIVER *pMCDDriver)
|
|
{
|
|
|
|
MCDBG_PRINT( "MCDrvGetEntryPoints\n");
|
|
|
|
if (pMCDDriver->ulSize < sizeof(MCDDRIVER))
|
|
return FALSE;
|
|
|
|
// Required functions (always)
|
|
pMCDDriver->pMCDrvInfo = MCDrvInfo;
|
|
pMCDDriver->pMCDrvDescribePixelFormat = MCDrvDescribePixelFormat;
|
|
pMCDDriver->pMCDrvCreateContext = MCDrvCreateContext;
|
|
pMCDDriver->pMCDrvDeleteContext = MCDrvDeleteContext;
|
|
pMCDDriver->pMCDrvBindContext = MCDrvBindContext;
|
|
pMCDDriver->pMCDrvDraw = MCDrvDraw;
|
|
pMCDDriver->pMCDrvClear = MCDrvClear;
|
|
pMCDDriver->pMCDrvState = MCDrvState;
|
|
pMCDDriver->pMCDrvSpan = MCDrvSpan;
|
|
pMCDDriver->pMCDrvTrackWindow = MCDrvTrackWindow;
|
|
pMCDDriver->pMCDrvAllocBuffers = MCDrvAllocBuffers;
|
|
|
|
// Required for NT only
|
|
pMCDDriver->pMCDrvGetHdev = MCDrvGetHdev;
|
|
|
|
// Required functions (conditionally)
|
|
// required for double-buffered pixel formats
|
|
pMCDDriver->pMCDrvSwap = MCDrvSwap;
|
|
// required for clipping
|
|
pMCDDriver->pMCDrvViewport = MCDrvViewport;
|
|
|
|
// Optional functions
|
|
// if no entry for MCDrvDescribeLayerPlane, MCD will not call driver for layer plane stuff
|
|
// pMCDDriver->pMCDrvSetLayerPalette = MCDrvSetLayerPalette;
|
|
// pMCDDriver->pMCDrvDescribeLayerPlane = MCDrvDescribeLayerPlane;
|
|
pMCDDriver->pMCDrvCreateMem = MCDrvCreateMem;
|
|
pMCDDriver->pMCDrvDeleteMem = MCDrvDeleteMem;
|
|
pMCDDriver->pMCDrvGetBuffers = MCDrvGetBuffers;
|
|
pMCDDriver->pMCDrvSync = MCDrvSync;
|
|
pMCDDriver->pMCDrvCreateTexture = MCDrvCreateTexture;
|
|
pMCDDriver->pMCDrvDeleteTexture = MCDrvDeleteTexture;
|
|
pMCDDriver->pMCDrvUpdateSubTexture = MCDrvUpdateSubTexture;
|
|
pMCDDriver->pMCDrvUpdateTexturePalette = MCDrvUpdateTexturePalette;
|
|
pMCDDriver->pMCDrvUpdateTexturePriority = MCDrvUpdateTexturePriority;
|
|
pMCDDriver->pMCDrvUpdateTextureState = MCDrvUpdateTextureState;
|
|
pMCDDriver->pMCDrvTextureStatus = MCDrvTextureStatus;
|
|
// pMCDDriver->pMCDrvDrawPixels = MCDrvDummyDrvDrawPixels;
|
|
// pMCDDriver->pMCDrvReadPixels = MCDrvDummyDrvReadPixels;
|
|
// pMCDDriver->pMCDrvCopyPixels = MCDrvDummyDrvCopyPixels;
|
|
// pMCDDriver->pMCDrvPixelMap = MCDrvDummyDrvPixelMap;
|
|
|
|
return TRUE;
|
|
}
|
|
|