/******************************Module*Header**********************************\ * * ************************** * * DirectDraw SAMPLE CODE * * ************************** * * Module Name: ddsurf.c * * Content: DirectDraw surfaces creation/destructions callbacks * * Copyright (c) 1994-1999 3Dlabs Inc. Ltd. All rights reserved. * Copyright (c) 1995-2003 Microsoft Corporation. All rights reserved. \*****************************************************************************/ // This file needs the surface format table #include "glint.h" #include "dma.h" // This enum is used to lookup the correct entry in the table // for all the surface types the HAL cares about typedef enum tagDeviceFormatNum { HAL_8888_ALPHA = 0, HAL_8888_NOALPHA = 1, HAL_5551_ALPHA = 2, HAL_5551_NOALPHA = 3, HAL_4444 = 4, HAL_332 = 10, HAL_2321 = 18, HAL_CI8 = 28, HAL_CI4 = 29, HAL_565 = 30, HAL_YUV444 = 34, HAL_YUV422 = 35, HAL_L8 = 36, HAL_A8L8 = 37, HAL_A4L4 = 38, HAL_A8 = 39, HAL_MVCA = 40, HAL_MVSU = 41, HAL_MVSB = 42, HAL_UNKNOWN = 255, } DeviceFormatNum; static P3_SURF_FORMAT SurfaceFormats[MAX_SURFACE_FORMATS] = { // If there are multiple formats, the one with the alpha is listed first. // Format 0 (32 bit 8888) // Always 3 components for 888(8) textures. Red Green Blue Alpha bAlpha, P3RX Filter format /* 0 */ {SURF_8888, 32, __GLINT_32BITPIXEL, RGBA_COMPONENTS, LOG_2_32, 0xFF0000, 0xFF00, 0xFF, 0xFF000000, TRUE, SURF_FILTER_8888_OR_YUV, SURF_DITHER_8888, "R8G8B8A8" }, /* 1 */ {SURF_8888, 32, __GLINT_32BITPIXEL, RGBA_COMPONENTS, LOG_2_32, 0xFF0000, 0xFF00, 0xFF, 0x00000000, FALSE, SURF_FILTER_888, SURF_DITHER_8888, "R8G8B8x8" }, // Format 1 (16 bit 5551) /* 2 */ {SURF_5551_FRONT, 16, __GLINT_16BITPIXEL, RGBA_COMPONENTS, LOG_2_16, 0x7C00, 0x03E0, 0x001F, 0x8000, TRUE, SURF_FILTER_5551, SURF_DITHER_5551, "R5G5B5A1" }, /* 3 */ {SURF_5551_FRONT, 16, __GLINT_16BITPIXEL, RGB_COMPONENTS, LOG_2_16, 0x7C00, 0x03E0, 0x001F, 0x0, FALSE, SURF_FILTER_5551, SURF_DITHER_5551, "R5G5B5x1" }, // Format 2 (16 bit 4444) /* 4 */ {SURF_4444, 16, __GLINT_16BITPIXEL, RGBA_COMPONENTS, LOG_2_16, 0xF00, 0xF0, 0xF, 0xF000, TRUE, SURF_FILTER_4444, SURF_DITHER_4444, "R4G4B4A4" }, /* 5 */ {SURF_4444, 16, __GLINT_16BITPIXEL, RGBA_COMPONENTS, LOG_2_16, 0xF00, 0xF0, 0xF, 0xF000, TRUE, SURF_FILTER_4444, SURF_DITHER_4444, "R4G4B4x4" }, // Format 3 (16 bit 4444 Front) /* 6 */ {SURF_4444_FRONT, 0, 0, COMPONENTS_DONT_CARE, 0, 0, 0, 0, 0, 0, SURF_FILTER_4444, SURF_DITHER_4444, "R4G4B4A4" }, /* 7 */ {SURF_4444_FRONT, 0, 0, COMPONENTS_DONT_CARE, 0, 0, 0, 0, 0, 0, SURF_FILTER_4444, SURF_DITHER_4444, "R4G4B4x4" }, // Format 4 (16 bit 4444 Back) /* 8 */ {SURF_4444_BACK, 0, 0, COMPONENTS_DONT_CARE, 0, 0, 0, 0, 0, 0, SURF_FILTER_4444, SURF_DITHER_4444, "R4G4B4A4" }, /* 9 */ {SURF_4444_BACK, 0, 0, COMPONENTS_DONT_CARE, 0, 0, 0, 0, 0, 0, SURF_FILTER_4444, SURF_DITHER_4444, "R4G4B4x4" }, // Format 5 (8 bit 332 Front) /* 10 */ {SURF_332_FRONT, 8, __GLINT_8BITPIXEL, RGB_COMPONENTS, LOG_2_8, 0xE0, 0x1C, 0x3, 0, FALSE, SURF_FILTER_332, SURF_DITHER_332, "R3G3B2" }, /* 11 */ {SURF_332_FRONT, 0, 0, COMPONENTS_DONT_CARE, 0, 0, 0, 0, 0, 0, SURF_FILTER_332, SURF_DITHER_332, "R3G3B2" }, // Format 6 (8 bit 332 back) /* 12 */ {SURF_332_BACK, 0, 0, COMPONENTS_DONT_CARE, 0, 0, 0, 0, 0, 0, SURF_FILTER_332, SURF_DITHER_332, "R3G3B2" }, /* 13 */ {SURF_332_BACK, 0, 0, COMPONENTS_DONT_CARE, 0, 0, 0, 0, 0, 0, SURF_FILTER_332, SURF_DITHER_332, "R3G3B2" }, // Format 7 (4 bit 121 front) /* 14 */ {SURF_121_FRONT, 0, 0, COMPONENTS_DONT_CARE, 0, 0, 0, 0, 0, 0, SURF_FILTER_INVALID, SURF_DITHER_INVALID, "R1G2B1" }, /* 15 */ {SURF_121_FRONT, 0, 0, COMPONENTS_DONT_CARE, 0, 0, 0, 0, 0, 0, SURF_FILTER_INVALID, SURF_DITHER_INVALID, "R1G2B1" }, // Format 8 (4 bit 121 back) /* 16 */ {SURF_121_BACK, 0, 0, COMPONENTS_DONT_CARE, 0, 0, 0, 0, 0, 0, SURF_FILTER_INVALID, SURF_DITHER_INVALID, "R1G2B1" }, /* 17 */ {SURF_121_BACK, 0, 0, COMPONENTS_DONT_CARE, 0, 0, 0, 0, 0, 0, SURF_FILTER_INVALID, SURF_DITHER_INVALID, "R1G2B1" }, // Format 9 (8 bit 2321 front) /* 18 */ {SURF_2321_FRONT, 8, __GLINT_8BITPIXEL, RGBA_COMPONENTS, LOG_2_8, 0xC0, 0x38, 0x6, 0x1, TRUE, SURF_FILTER_INVALID, SURF_DITHER_INVALID, "R2G3B2A1" }, /* 19 */ {SURF_2321_FRONT, 0, 0, COMPONENTS_DONT_CARE, 0, 0, 0, 0, 0, 0, SURF_FILTER_INVALID, SURF_DITHER_INVALID, "R2G3B2x1" }, // Format 10 (8 bit 2321 back) /* 20 */ {SURF_2321_BACK, 0, 0, COMPONENTS_DONT_CARE, 0, 0, 0, 0, 0, 0, SURF_FILTER_INVALID, SURF_DITHER_INVALID, "R2G3B2A1" }, /* 21 */ {SURF_2321_BACK, 0, 0, COMPONENTS_DONT_CARE, 0, 0, 0, 0, 0, 0, SURF_FILTER_INVALID, SURF_DITHER_INVALID, "R2G3B2x1" }, // Format 11 (8 bit 232 front off) /* 22 */ {SURF_232_FRONTOFF, 0, 0, COMPONENTS_DONT_CARE, 0, 0, 0, 0, 0, 0, SURF_FILTER_INVALID, SURF_DITHER_INVALID, "R2G3B2x1" }, /* 23 */ {SURF_232_FRONTOFF, 0, 0, COMPONENTS_DONT_CARE, 0, 0, 0, 0, 0, 0, SURF_FILTER_INVALID, SURF_DITHER_INVALID, "R2G3B2x1" }, // Format 12 (8 bit 232 back off) /* 24 */ {SURF_232_BACKOFF, 0, 0, COMPONENTS_DONT_CARE, 0, 0, 0, 0, 0, 0, SURF_FILTER_INVALID, SURF_DITHER_INVALID, "R2G3B2x1" }, /* 25 */ {SURF_232_BACKOFF, 0, 0, COMPONENTS_DONT_CARE, 0, 0, 0, 0, 0, 0, SURF_FILTER_INVALID, SURF_DITHER_INVALID, "R2G3B2x1" }, // Format 13 (5551 back) /* 26 */ {SURF_5551_BACK, 0, 0, COMPONENTS_DONT_CARE, 0, 0, 0, 0, 0, 0, SURF_FILTER_5551, SURF_DITHER_5551, "R5G5B5A1" }, /* 27 */ {SURF_5551_BACK, 0, 0, COMPONENTS_DONT_CARE, 0, 0, 0, 0, 0, 0, SURF_FILTER_5551, SURF_DITHER_5551, "R5G5B5x1" }, // Format 14 (CI8) /* 28 */ {SURF_CI8, 8, __GLINT_8BITPIXEL, RGBA_COMPONENTS, LOG_2_8, 0, 0, 0, 0, TRUE, SURF_FILTER_8888_OR_YUV, SURF_DITHER_I8, "I8" }, // Format 15 (CI4) /* 29 */ {SURF_CI4, 4, __GLINT_4BITPIXEL, RGBA_COMPONENTS, LOG_2_4, 0, 0, 0, 0, TRUE, SURF_FILTER_8888_OR_YUV, SURF_DITHER_INVALID, "I4" }, // Format 16 (565 front) /* 30 */ {SURF_565_FRONT, 16, __GLINT_16BITPIXEL, RGB_COMPONENTS, LOG_2_16, 0xF800, 0x07E0, 0x001F, 0, FALSE, SURF_FILTER_565, SURF_DITHER_565, "R5G6B5" }, /* 31 */ {SURF_565_FRONT, 0, 0, COMPONENTS_DONT_CARE, 0, 0, 0, 0, 0, 0, SURF_FILTER_565, SURF_DITHER_565, "R5G6B5" }, // Format 17 (565 back) /* 32 */ {SURF_565_BACK, 0, 0, COMPONENTS_DONT_CARE, 0, 0, 0, 0, 0, 0, SURF_FILTER_565, SURF_DITHER_565, "R5G6B5" }, /* 33 */ {SURF_565_BACK, 0, 0, COMPONENTS_DONT_CARE, 0, 0, 0, 0, 0, 0, SURF_FILTER_565, SURF_DITHER_565, "R5G6B5" }, // Format 18 (YUV 444) /* 34 */ {SURF_YUV444, 32, __GLINT_16BITPIXEL, RGBA_COMPONENTS, LOG_2_16, 0, 0, 0, 0, TRUE, SURF_FILTER_8888_OR_YUV, SURF_DITHER_INVALID, "YUV444" }, // Format 19 (YUV 422) /* 35 */ {SURF_YUV422, 16, __GLINT_16BITPIXEL, RGB_COMPONENTS, LOG_2_32, 0, 0, 0, 0, FALSE, SURF_FILTER_8888_OR_YUV, SURF_DITHER_INVALID, "YUV422" }, // Format 100 (L8) /* 36 */ {SURF_L8, 8, __GLINT_8BITPIXEL, RGB_COMPONENTS, LOG_2_8, 0, 0, 0, 0, FALSE, SURF_FILTER_L8, SURF_DITHER_INVALID, "L8" }, // Format 101 (A8L8) /* 37 */ {SURF_A8L8, 16, __GLINT_16BITPIXEL, RGB_COMPONENTS, LOG_2_16, 0, 0, 0, 0, TRUE, SURF_FILTER_A8L8, SURF_DITHER_INVALID, "A8L8" }, // Format 102 (A4L4) /* 38 */ {SURF_A4L4, 16, __GLINT_8BITPIXEL, RGB_COMPONENTS, LOG_2_8, 0, 0, 0, 0, TRUE, SURF_FILTER_A4L4, SURF_DITHER_INVALID, "A4L4" }, // Format 103 (A8) /* 39 */ {SURF_A8, 8, __GLINT_8BITPIXEL, RGB_COMPONENTS, LOG_2_8, 0, 0, 0, 0, TRUE, SURF_FILTER_A8, SURF_DITHER_INVALID, "A8" }, // Format 104 (A8) MVCA /* 40 */ {SURF_MVCA, 32, __GLINT_32BITPIXEL, RGB_COMPONENTS, LOG_2_32, 0, 0, 0, 0, TRUE, SURF_FILTER_8888_OR_YUV, SURF_DITHER_INVALID, "MVCA" }, // Format 105 (A8) MVSU /* 41 */ {SURF_MVSU, 32, __GLINT_32BITPIXEL, RGB_COMPONENTS, LOG_2_32, 0, 0, 0, 0, TRUE, SURF_FILTER_8888_OR_YUV, SURF_DITHER_INVALID, "MVSU" }, // Format 106 (A8) MVSB /* 42 */ {SURF_MVSB, 32, __GLINT_32BITPIXEL, RGB_COMPONENTS, LOG_2_32, 0, 0, 0, 0, TRUE, SURF_FILTER_8888_OR_YUV, SURF_DITHER_INVALID, "MVSB" } }; #define MAKE_DWORD_ALIGNED(n) ( ((n) % 4) ? ((n) + 4 - ((n) % 4)) : (n) ) #define MAKE_QWORD_ALIGNED(n) ( ((n) % 8) ? ((n) + 8 - ((n) % 8)) : (n) ) //----------------------------------------------------------------------------- // // _DD_SUR_GetSurfaceFormat // //----------------------------------------------------------------------------- P3_SURF_FORMAT* _DD_SUR_GetSurfaceFormat( LPDDRAWI_DDRAWSURFACE_LCL pLcl) { DeviceFormatNum HALDeviceFormat = HAL_UNKNOWN; // The default if (pLcl) { DDPIXELFORMAT* pPixFormat = DDSurf_GetPixelFormat(pLcl); if (pPixFormat->dwFlags & DDPF_FOURCC) { switch( pPixFormat->dwFourCC) { case FOURCC_MVCA: HALDeviceFormat = HAL_MVCA; break; case FOURCC_MVSU: HALDeviceFormat = HAL_MVSU; break; case FOURCC_MVSB: HALDeviceFormat = HAL_MVSB; break; case FOURCC_YUV422: HALDeviceFormat = HAL_YUV422; break; case FOURCC_YUV411: HALDeviceFormat = HAL_YUV444; break; } //switch } else if (pPixFormat->dwFlags & DDPF_PALETTEINDEXED4) { HALDeviceFormat = HAL_CI4; } else if (pPixFormat->dwFlags & DDPF_PALETTEINDEXED8) { HALDeviceFormat = HAL_CI8; } else if (pPixFormat->dwFlags & DDPF_LUMINANCE) { switch(pPixFormat->dwRGBBitCount) { case 8: if (pPixFormat->dwFlags & DDPF_ALPHAPIXELS) { HALDeviceFormat = HAL_A4L4; } else { HALDeviceFormat = HAL_L8; } break; case 16: HALDeviceFormat = HAL_A8L8; break; default: HALDeviceFormat = HAL_UNKNOWN; break; } // switch } else if (pPixFormat->dwFlags & DDPF_ALPHA) { // Alpha only format switch(pPixFormat->dwAlphaBitDepth) { case 8: HALDeviceFormat = HAL_A8; break; default: HALDeviceFormat = HAL_UNKNOWN; break; } } else { switch(pPixFormat->dwRGBBitCount) { case 32: case 24: if (pPixFormat->dwRGBAlphaBitMask != 0) { HALDeviceFormat = HAL_8888_ALPHA; } else { HALDeviceFormat = HAL_8888_NOALPHA; } break; case 16: switch (pPixFormat->dwRBitMask) { case 0xf00: HALDeviceFormat = HAL_4444; break; case 0x7c00: if (pPixFormat->dwRGBAlphaBitMask != 0) { HALDeviceFormat = HAL_5551_ALPHA; } else { HALDeviceFormat = HAL_5551_NOALPHA; } break; default: HALDeviceFormat = HAL_565; break; } break; case 8: if (pPixFormat->dwRBitMask != 0xE0) { HALDeviceFormat = HAL_2321; } else { HALDeviceFormat = HAL_332; } break; case 0: HALDeviceFormat = HAL_CI8; break; default: DISPDBG((ERRLVL,"_DD_SUR_GetSurfaceFormat: " "Invalid Surface Format")); break; } // switch } // if } #if DBG if (HALDeviceFormat == HAL_UNKNOWN) { DISPDBG((ERRLVL,"ERROR: Failed to pick a valid surface format!")); } if(SurfaceFormats[HALDeviceFormat].dwBitsPerPixel == 0) { DISPDBG((ERRLVL,"ERROR: Chosen surface format that isn't defined " "in the table!")); } #endif // DBG if (HALDeviceFormat == HAL_UNKNOWN) { // Don't know what it is - return a valid type. return &SurfaceFormats[0]; } else { // Return a pointer to the correct line in the table return &SurfaceFormats[HALDeviceFormat]; } } // _DD_SUR_GetSurfaceFormat //--------------------------------------------------------------------------- // BOOL __SUR_bComparePixelFormat // // Function used to compare 2 pixels formats for equality. This is a // helper function to __SUR_bCheckTextureFormat. A return value of TRUE // indicates equality // //--------------------------------------------------------------------------- BOOL __SUR_bComparePixelFormat( LPDDPIXELFORMAT lpddpf1, LPDDPIXELFORMAT lpddpf2) { if (lpddpf1->dwFlags != lpddpf2->dwFlags) { return FALSE; } // same bitcount for non-YUV surfaces? if (!(lpddpf1->dwFlags & (DDPF_YUV | DDPF_FOURCC))) { if (lpddpf1->dwRGBBitCount != lpddpf2->dwRGBBitCount ) { return FALSE; } } // same RGB properties? if (lpddpf1->dwFlags & DDPF_RGB) { if ((lpddpf1->dwRBitMask != lpddpf2->dwRBitMask) || (lpddpf1->dwGBitMask != lpddpf2->dwGBitMask) || (lpddpf1->dwBBitMask != lpddpf2->dwBBitMask) || (lpddpf1->dwRGBAlphaBitMask != lpddpf2->dwRGBAlphaBitMask)) { return FALSE; } } // same YUV properties? if (lpddpf1->dwFlags & DDPF_YUV) { if ((lpddpf1->dwFourCC != lpddpf2->dwFourCC) || (lpddpf1->dwYUVBitCount != lpddpf2->dwYUVBitCount) || (lpddpf1->dwYBitMask != lpddpf2->dwYBitMask) || (lpddpf1->dwUBitMask != lpddpf2->dwUBitMask) || (lpddpf1->dwVBitMask != lpddpf2->dwVBitMask) || (lpddpf1->dwYUVAlphaBitMask != lpddpf2->dwYUVAlphaBitMask)) { return FALSE; } } else if (lpddpf1->dwFlags & DDPF_FOURCC) { if (lpddpf1->dwFourCC != lpddpf2->dwFourCC) { return FALSE; } } // If Interleaved Z then check Z bit masks are the same if (lpddpf1->dwFlags & DDPF_ZPIXELS) { if (lpddpf1->dwRGBZBitMask != lpddpf2->dwRGBZBitMask) { return FALSE; } } return TRUE; } // __SUR_bComparePixelFormat //--------------------------------------------------------------------------- // // BOOL __SUR_bCheckTextureFormat // // Function used to determine if a texture format is supported. It traverses // the deviceTextureFormats list. We use this in DdCanCreateSurface. A // return value of TRUE indicates that we do support the requested texture // format. // //--------------------------------------------------------------------------- BOOL __SUR_bCheckTextureFormat( P3_THUNKEDDATA *pThisDisplay, LPDDPIXELFORMAT lpddpf) { DWORD i; // Run the list for a matching format , we already built the list (when // the driver was loaded) and stored it in pThisDisplay with // __D3D_BuildTextureFormatsP3 in _D3DHALCreateDriver (d3d.c) // Notice the special handling for paletted textures as described in // __D3D_BuildTextureFormatsP3 (thats why we loop until <= , not just // until < ). for (i=0; i <= pThisDisplay->dwNumTextureFormats; i++) { if (__SUR_bComparePixelFormat( lpddpf, &pThisDisplay->TextureFormats[i].ddpfPixelFormat)) { return TRUE; } } return FALSE; } // __SUR_bCheckTextureFormat //--------------------------------------------------------------------------- // // DWORD __SUR_bSurfPlacement // // Function used to determine if a surface should be placed at the front or // at the back of our video memory heap. // Returns the MEM3DL_FRONT and MEM3DL_BACK values. // //--------------------------------------------------------------------------- DWORD __SUR_bSurfPlacement( LPDDRAWI_DDRAWSURFACE_LCL psurf, DDSURFACEDESC *lpDDSurfaceDesc) { static BOOL bBufferToggle = TRUE; DWORD dwResult; if (psurf->ddsCaps.dwCaps & DDSCAPS_TEXTURE) { DWORD dwTexturePlacement; // They might have passed a DDSD2 in a DDSD1 structure. if (lpDDSurfaceDesc && (lpDDSurfaceDesc->dwSize == sizeof(DDSURFACEDESC2))) { DDSURFACEDESC2* pDesc2 = (DDSURFACEDESC2*)lpDDSurfaceDesc; // Check for the application hint on texture stage placement if (!(pDesc2->ddsCaps.dwCaps & DDSCAPS_MIPMAP)) { if (pDesc2->dwFlags & DDSD_TEXTURESTAGE) { dwTexturePlacement = pDesc2->dwTextureStage; // Put it somewhere sensible if it // is in a large stage number if (dwTexturePlacement > 1) { // Toggle all entries above 1 so that they // jump between banks. dwTexturePlacement = (dwTexturePlacement ^ 1) & 0x1; } } else { // No stage hint. PingPong dwTexturePlacement = bBufferToggle; bBufferToggle = !bBufferToggle; } } else { // No stage hint. PingPong dwTexturePlacement = bBufferToggle; bBufferToggle = !bBufferToggle; } } else { // No DDSD2, PingPong dwTexturePlacement = bBufferToggle; bBufferToggle = !bBufferToggle; } // Jump up and down in the one heap if (dwTexturePlacement == 0) { dwResult = MEM3DL_FRONT; } else { dwResult = MEM3DL_BACK; } } // Not a texture else { dwResult = MEM3DL_FRONT; } return dwResult; } // __SUR_bSurfPlacement //-----------------------------Public Routine---------------------------------- // // DdCanCreateSurface // // Indicates whether the driver can create a surface of the specified // surface description // // DdCanCreateSurface should check the surface description to which // lpDDSurfaceDesc points to determine if the driver can support the format and // capabilities of the requested surface for the mode that the driver is // currently in. The driver should return DD_OK in ddRVal if it supports the // surface; otherwise, it should return the DDERR_Xxx error code that best // describes why it does not support the surface. // // The bIsDifferentPixelFormat member is unreliable for z-buffers. Drivers // should use bIsDifferentPixelFormat only when they have first checked that // the specified surface is not a z-buffer. Drivers can perform this check by // determining whether the DDSCAPS_ZBUFFER flag is set in lpDDSurfaceDesc // ddsCaps.dwCaps. // // Parameters // // pccsd // Points to the DD_CANCREATESURFACEDATA structure containing the // information required for the driver to determine whether a surface // can be created. // // .lpDD // Points to the DD_DIRECTDRAW_GLOBAL structure representing the // DirectDraw object. // .lpDDSurfaceDesc // Points to a DDSURFACEDESC structure that contains a // description of the surface to be created. // .bIsDifferentPixelFormat // Indicates whether the pixel format of the surface to be // created differs from the primary surface. // .ddRVal // Specifies the location in which the driver writes the return // value of the DdCanCreateSurface callback. A return code of // DD_OK indicates success. // .CanCreateSurface // This is unused on Windows 2000. // //----------------------------------------------------------------------------- DWORD CALLBACK DdCanCreateSurface( LPDDHAL_CANCREATESURFACEDATA pccsd ) { P3_THUNKEDDATA* pThisDisplay; DBG_CB_ENTRY(DdCanCreateSurface); GET_THUNKEDDATA(pThisDisplay, pccsd->lpDD); VALIDATE_MODE_AND_STATE(pThisDisplay); // ************************* Z BUFFERS ******************************* // We support 15,16,24 and 32 bits Z-buffers // (wo accounting for stencil bits) on PERMEDIA3 if ((pccsd->lpDDSurfaceDesc->ddsCaps.dwCaps & DDSCAPS_ZBUFFER) && (pccsd->lpDDSurfaceDesc->ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY)) { DWORD dwZBitDepth; // Check out the case of a z buffer with a pixel format // Complex surfaces aren't allowed to have stencil bits. In // this case we take the pixel z depth from the old place - the // surface desc. if ((pccsd->lpDDSurfaceDesc->ddsCaps.dwCaps & DDSCAPS_COMPLEX) || (pccsd->lpDDSurfaceDesc->dwFlags & DDSD_ZBUFFERBITDEPTH) ) { dwZBitDepth = pccsd->lpDDSurfaceDesc->dwZBufferBitDepth; } else { // On DX 6 the Z Bit depth is stored in the Pixel Format. dwZBitDepth = pccsd->lpDDSurfaceDesc->ddpfPixelFormat.dwZBufferBitDepth; } // Notice we have to check for a dwZBitDepth of 16 or 32 even if a // stencil buffer is present. dwZBufferBitDepth in this case will be // the sum of the z buffer and the stencil buffer bit depth. if ((dwZBitDepth == 16) || (dwZBitDepth == 32)) { pccsd->ddRVal = DD_OK; } else { DISPDBG((WRNLVL,"DdCanCreateSurface ERROR: " "Depth buffer not 16 or 32 Bits! (%d)", dwZBitDepth)); pccsd->ddRVal = DDERR_INVALIDPIXELFORMAT; } DBG_CB_EXIT(DdCanCreateSurface, pccsd->ddRVal); return DDHAL_DRIVER_HANDLED; } // *********************** 3D RENDER TARGETS *************************** if (pccsd->lpDDSurfaceDesc->ddsCaps.dwCaps & DDSCAPS_3DDEVICE) { // We are going to use this surface as a rendering target // Notice that this will also cover the case when we're // trying to create a vidmem texture that will also be used // as a rendertarget (as we go thorugh this path before // DDSCAPS_TEXTURE-cap surfaces are processed) if (!pccsd->bIsDifferentPixelFormat) { // we have the same format as the primary . If this is true, // on DX7 we won't have the ddpfPixelFormat fielded at all. // But we do support rendertargets and textures of the same // format as our possible primaries so we return DD_OK DISPDBG((DBGLVL, "DdCanCreateSurface OK: " "Same as primary format for " "rendertarget surface" )); pccsd->ddRVal = DD_OK; } else if( pccsd->lpDDSurfaceDesc->ddpfPixelFormat.dwFlags & DDPF_RGB ) { DDPIXELFORMAT *pPixFmt = &pccsd->lpDDSurfaceDesc->ddpfPixelFormat; // Only 32 and 16 (565) RGB modes allowed. switch (pPixFmt->dwRGBBitCount) { case 32: DISPDBG((DBGLVL, "DdCanCreateSurface OK: " "32-bit RGB format for " "rendertarget surface" )); pccsd->ddRVal = DD_OK; break; case 16: if ((pPixFmt->dwRBitMask == 0xF800) && (pPixFmt->dwGBitMask == 0x07E0) && (pPixFmt->dwBBitMask == 0x001F)) { DISPDBG((DBGLVL, "DdCanCreateSurface OK: " "16-bit 565 RGB format for " "rendertarget surface" )); pccsd->ddRVal = DD_OK; } else { DISPDBG((WRNLVL, "DdCanCreateSurface ERROR: " "NOT 16-bit 565 RGB format for " "16BPP rendertarget surface" )); pccsd->ddRVal = DDERR_INVALIDPIXELFORMAT; } break; default: DISPDBG((WRNLVL, "DdCanCreateSurface ERROR: " "RGB rendertarget not 16 (565) " "or 32 bit - wrong pixel format" )); pccsd->ddRVal = DDERR_INVALIDPIXELFORMAT; break; } } else { DISPDBG((WRNLVL, "DdCanCreateSurface ERROR: " "Rendertarget not an RGB Surface" " - wrong pixel format" )); pccsd->ddRVal = DDERR_INVALIDPIXELFORMAT; } DBG_CB_EXIT(DdCanCreateSurface, pccsd->ddRVal); return DDHAL_DRIVER_HANDLED; } // *************************** TEXTURES ************************** if(pccsd->lpDDSurfaceDesc->ddsCaps.dwCaps & DDSCAPS_TEXTURE) { // Notice that the case when we're trying to create a vidmem // texture that will also be used as a rendertarget has already // been taken care of when processing the 3D rendertargets case // as their valid formats are a subset of the valid texture formats if (!pccsd->bIsDifferentPixelFormat) { // we have the same format as the primary . If this is true, // on DX7 we won't have the ddpfPixelFormat fielded at all. // but all primary formats are valid for this driver as // texture formats as well, so succeed this call DISPDBG((DBGLVL, "DdCanCreateSurface OK: " "Same as primary format for " "texture surface" )); pccsd->ddRVal = DD_OK; } // if the surface is going to be a texture verify it matches one // of the supported texture formats (already stored in pThisDisplay) else if (__SUR_bCheckTextureFormat( pThisDisplay, &pccsd->lpDDSurfaceDesc->ddpfPixelFormat)) { // texture surface is in one or our supported texture formats DISPDBG((DBGLVL, " Texture Surface - OK" )); pccsd->ddRVal = DD_OK; } else { // we don't support this kind of texture format DISPDBG((WRNLVL, "DdCanCreateSurface ERROR: " "Texture Surface format not supported" )); pccsd->ddRVal = DDERR_INVALIDPIXELFORMAT; } DBG_CB_EXIT(DdCanCreateSurface, pccsd->ddRVal); return DDHAL_DRIVER_HANDLED; } // *********************************************************************** // * OTHER OFFSCREEN SURFACES THAT ARE DIFFERENT FROM THE PRIMARY FORMAT * // *********************************************************************** if (pccsd->bIsDifferentPixelFormat) { DISPDBG((DBGLVL,"Pixel Format is different to primary")); if(pccsd->lpDDSurfaceDesc->ddpfPixelFormat.dwFlags & DDPF_FOURCC) { DISPDBG((DBGLVL, " FourCC requested (%4.4hs, 0x%08lx)", (LPSTR) &pccsd->lpDDSurfaceDesc->ddpfPixelFormat.dwFourCC, pccsd->lpDDSurfaceDesc->ddpfPixelFormat.dwFourCC )); switch (pccsd->lpDDSurfaceDesc->ddpfPixelFormat.dwFourCC) { case FOURCC_YUV422: DISPDBG((WRNLVL,"DdCanCreateSurface OK: " "Surface requested is YUV422")); pccsd->lpDDSurfaceDesc->ddpfPixelFormat.dwYUVBitCount = 16; pccsd->ddRVal = DD_OK; break; // Disabled for now. case FOURCC_YUV411: DISPDBG((WRNLVL,"DdCanCreateSurface ERROR: " "Surface requested is YUV411 - Disabled")); pccsd->lpDDSurfaceDesc->ddpfPixelFormat.dwYUVBitCount = 32; pccsd->ddRVal = DDERR_INVALIDPIXELFORMAT; break; default: DISPDBG((WRNLVL,"DdCanCreateSurface ERROR: " "Invalid FOURCC requested, refusing")); pccsd->ddRVal = DDERR_INVALIDPIXELFORMAT; break; } DBG_CB_EXIT(DdCanCreateSurface, pccsd->ddRVal); return DDHAL_DRIVER_HANDLED; } //@@BEGIN_DDKSPLIT // azn check if the following variations are now still needed //@@END_DDKSPLIT // Luminance texture support else if( (pccsd->lpDDSurfaceDesc->ddpfPixelFormat.dwFlags & DDPF_LUMINANCE) && !(pccsd->lpDDSurfaceDesc->ddsCaps.dwCaps & DDSCAPS_OVERLAY) ) { DDPIXELFORMAT *pddpfCur; // Only 16 and 8-bit modes allowed. pddpfCur = &(pccsd->lpDDSurfaceDesc->ddpfPixelFormat); if (pddpfCur->dwLuminanceBitCount == 8) { // Check for L8 if (!(pccsd->lpDDSurfaceDesc->ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS)) { DISPDBG((DBGLVL, "DdCanCreateSurface OK: " " 8 Bit Luminance surface")); pccsd->ddRVal = DD_OK; } // Must be A4:L4 else { DISPDBG((DBGLVL, "DdCanCreateSurface OK: " "4 Bit Luma + 4 Bit Alpha surface")); pccsd->ddRVal = DD_OK; } } // Check for A8L8 else if (pddpfCur->dwLuminanceBitCount == 16) { if (pccsd->lpDDSurfaceDesc->ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS) { DISPDBG((DBGLVL, "DdCanCreateSurface OK: " " 16 Bit Luminance + Alpha Surface")); pccsd->ddRVal = DD_OK; } else { DISPDBG((WRNLVL, "DdCanCreateSurface ERROR: " "Bad A8L8 format" )); pccsd->ddRVal = DDERR_INVALIDPIXELFORMAT; } } else { DISPDBG((WRNLVL, "DdCanCreateSurface ERROR: " "Unknown luminance texture" )); pccsd->ddRVal = DDERR_INVALIDPIXELFORMAT; } DBG_CB_EXIT(DdCanCreateSurface, pccsd->ddRVal); return DDHAL_DRIVER_HANDLED; } else if( (pccsd->lpDDSurfaceDesc->ddpfPixelFormat.dwFlags & DDPF_ALPHA) && !(pccsd->lpDDSurfaceDesc->ddsCaps.dwCaps & DDSCAPS_OVERLAY)) { DDPIXELFORMAT *pddpfCur; pddpfCur = &(pccsd->lpDDSurfaceDesc->ddpfPixelFormat); if (pddpfCur->dwAlphaBitDepth == 8) { DISPDBG((DBGLVL, "DdCanCreateSurface OK: " "8 Bit Alpha surface")); pccsd->ddRVal = DD_OK; } else { DISPDBG((WRNLVL, "DdCanCreateSurface ERROR: " "pddpfCur->dwAlphaBitDepth != 8" )); pccsd->ddRVal = DDERR_INVALIDPIXELFORMAT; } DBG_CB_EXIT(DdCanCreateSurface, pccsd->ddRVal); return DDHAL_DRIVER_HANDLED; } else if( pccsd->lpDDSurfaceDesc->ddpfPixelFormat.dwFlags & DDPF_RGB ) { DDPIXELFORMAT *pddpfCur; // Only 32, 16 and 8-bit modes allowed. pddpfCur = &(pccsd->lpDDSurfaceDesc->ddpfPixelFormat); switch ( pddpfCur->dwRGBBitCount ) { case 32: DISPDBG((DBGLVL, "DdCanCreateSurface OK: " "RGB 32-bit surface" )); pccsd->ddRVal = DD_OK; break; case 16: DISPDBG((DBGLVL, "DdCanCreateSurface OK: " "RGB 16-bit surface" )); pccsd->ddRVal = DD_OK; break; case 8: DISPDBG((DBGLVL, "DdCanCreateSurface OK: " "RGB 8-bit Surface" )); pccsd->ddRVal = DD_OK; break; default: DISPDBG((WRNLVL, "DdCanCreateSurface ERROR: " "RGB Surface - wrong pixel format" )); pccsd->ddRVal = DDERR_INVALIDPIXELFORMAT; break; } DBG_CB_EXIT(DdCanCreateSurface, pccsd->ddRVal); return DDHAL_DRIVER_HANDLED; } // Since its a different from the primary surface and doesn't fall // into any of the previous cases, we fail it DISPDBG((WRNLVL, "DdCanCreateSurface ERROR: " "Different from the primary surface but unknown" )); pccsd->ddRVal = DDERR_INVALIDPIXELFORMAT; DBG_CB_EXIT(DdCanCreateSurface, pccsd->ddRVal); return DDHAL_DRIVER_HANDLED; } // Same format as the primary, we succeed it anyway DISPDBG((DBGLVL, "DdCanCreateSurface OK: (Def) Same format as primary" )); pccsd->ddRVal = DD_OK; DBG_CB_EXIT(DdCanCreateSurface, pccsd->ddRVal); return DDHAL_DRIVER_HANDLED; } // DdCanCreateSurface //-----------------------------Public Routine---------------------------------- // // DdCreateSurface // // Creates a DirectDraw surface. // // The driver can allocate the surface memory itself or can request that // DirectDraw perform the memory management. If the driver performs the //allocation, it must do the following: // // Perform the allocation and write a valid pointer to the memory in the // fpVidMem member of the DD_SURFACE_GLOBAL structure. // If the surface has a FourCC format, write the pitch in the lPitch member of // the DD_SURFACE_GLOBAL and DDSURFACEDESC structures, and update the flags // accordingly. // // Otherwise, the driver can have DirectDraw allocate the surface by returning // one of the following values in fpVidMem: // // DDHAL_PLEASEALLOC_BLOCKSIZE requests that DirectDraw allocate the // surface memory from offscreen memory. // DDHAL_PLEASEALLOC_USERMEM requests that DirectDraw allocate the // surface memory from user memory. The // driver must also return the size in // bytes of the memory region in dwUserMemSize. // // For DirectDraw to perform the allocation of a surface with a FourCC format, // the driver must also return the pitch and x- and y-block sizes in lPitch, // dwBlockSizeX, and dwBlockSizeY, respectively. The pitch must be returned in // the lPitch member of both the DD_SURFACE_GLOBAL and DDSURFACEDESC structures. // For linear memory, the driver should set dwBlockSizeX to be the size in bytes // of the memory region and set dwBlockSizeY to 1. // // By default, the driver is not notified when a primary surface is created on // Windows 2000. However, if the driver supports GUID_NTPrivateDriverCaps and // the DDHAL_PRIVATECAP_NOTIFYPRIMARYCREATION flag is set, then the driver will // be notified. // // Parameters // // pcsd // Points to a DD_CREATESURFACEDATA structure that contains the // information required to create a surface. // // .lpDD // Points to the DD_DIRECTDRAW_GLOBAL structure representing the // driver. // .lpDDSurfaceDesc // Points to the DDSURFACEDESC structure describing the surface // that the driver should create. // .lplpSList // Points to a list of DD_SURFACE_LOCAL structures describing // the surface objects created by the driver. On Windows 2000, // there is usually only one entry in this array. However, if // the driver supports the Windows 95/98-style surface creation // techniques using DdGetDriverInfo with GUID_NTPrivateDriverCaps, // and the driver sets the DDHAL_PRIVATECAP_ATOMICSURFACECREATION // flag, the member will contain a list of surfaces (usually more // than one). // .dwSCnt // Specifies the number of surfaces in the list to which lplpSList // points. This value is usually 1 on Windows 2000. However, if // you support the Windows 95/Windows98-style surface creation // techniques using DdGetDriverInfo with GUID_NTPrivateDriverCaps, // the member will contain the actual number of surfaces in the // list (usually more than one). // .ddRVal // Specifies the location in which the driver writes the return // value of the DdCreateSurface callback. A return code of DD_OK // indicates success. // .CreateSurface // This is unused on Windows 2000. // //----------------------------------------------------------------------------- DWORD CALLBACK DdCreateSurface( LPDDHAL_CREATESURFACEDATA pcsd ) { int i; DWORD BitDepth; LPDDRAWI_DDRAWSURFACE_LCL psurf; LPDDRAWI_DDRAWSURFACE_GBL psurf_gbl; LPDDRAWI_DDRAWSURFACE_MORE psurf_more; BOOL bHandled = TRUE; BOOL bResize = FALSE; P3_THUNKEDDATA* pThisDisplay; DWORD dwExtraBytes; DBG_CB_ENTRY(DdCreateSurface); GET_THUNKEDDATA(pThisDisplay, pcsd->lpDD); VALIDATE_MODE_AND_STATE(pThisDisplay); STOP_SOFTWARE_CURSOR(pThisDisplay); DDRAW_OPERATION(pContext, pThisDisplay); for( i=0; i<(int)pcsd->dwSCnt; i++ ) { DDPIXELFORMAT* pPixFormat = NULL; psurf = pcsd->lplpSList[i]; psurf_gbl = psurf->lpGbl; psurf_more = psurf->lpSurfMore; // Dump debug info about the surface to be created DISPDBG((DBGLVL, "\nLooking at Surface %d of %d", i + 1, pcsd->dwSCnt)); DISPDBG((DBGLVL,"Surf dimensions: %d x %d", psurf_gbl->wWidth, psurf_gbl->wHeight )); DBGDUMP_DDRAWSURFACE_LCL(DBGLVL, psurf); DISPDBG((DBGLVL, "DdCreateSurface setting NULL")); psurf_gbl->fpVidMem = 0; // Get the bitdepth of the surface BitDepth = DDSurf_BitDepth(psurf); // All Z buffers need adjusting, and setting the correct bit depth if (DDSurf_HasPixelFormat(psurf->dwFlags)) { if (psurf_gbl->ddpfSurface.dwFlags & DDPF_ZBUFFER) { DISPDBG((DBGLVL,"Surface is Z Buffer")); BitDepth = psurf_gbl->ddpfSurface.dwZBufferBitDepth; // Force the pitch to the correct value - the DX runtime // sometimes sends us a duff value. psurf_gbl->lPitch = psurf_gbl->wWidth << ( BitDepth >> 4 ); // Ddraw surfaces in IA64 have to be DWORD aligned in their // pitch in order for emulation code to work correctly // And on X86 we declared surfaces will be DWORD aligned in // DrvGetDirectDrawInfo (vmiData.dwXXXXXAlign = 4) psurf_gbl->lPitch = MAKE_DWORD_ALIGNED(psurf_gbl->lPitch); } } // Determine if we need to resize the surface to make it fit. bResize = FALSE; // The surface is a YUV format surface if (DDSurf_HasPixelFormat(psurf->dwFlags)) { if (psurf_gbl->ddpfSurface.dwFlags & DDPF_FOURCC) { bResize = TRUE; switch( psurf_gbl->ddpfSurface.dwFourCC ) { case FOURCC_YUV422: DISPDBG((DBGLVL,"Surface is YUV422")); psurf_gbl->ddpfSurface.dwYUVBitCount = 16; BitDepth = 16; break; case FOURCC_YUV411: DISPDBG((DBGLVL,"Surface is YUV411")); psurf_gbl->ddpfSurface.dwYUVBitCount = 32; BitDepth = 32; break; default: // We should never get here, as CanCreateSurface will // validate the YUV format for us. DISPDBG((ERRLVL,"Trying to create an invalid YUV surface!")); break; } } } DISPDBG((DBGLVL,"Surface Pitch is: 0x%x", psurf_gbl->lPitch)); // This flag is set if the surface needs resizing. if (bResize) { DWORD dwNewWidth = psurf_gbl->wWidth; DWORD dwNewHeight = psurf_gbl->wHeight; DWORD dwHeightAlignment = 1; DWORD dwWidthAlignment = 1; DISPDBG((DBGLVL, "Resizing surface")); while ((dwNewWidth % dwWidthAlignment) != 0) dwNewWidth++; while ((dwNewHeight % dwHeightAlignment) != 0) dwNewHeight++; DISPDBG((DBGLVL,"Surface original = %d x %d, Surface new = %d x %d", psurf_gbl->wWidth, psurf_gbl->wHeight, dwNewWidth, dwNewHeight)); psurf_gbl->fpVidMem = (FLATPTR) DDHAL_PLEASEALLOC_BLOCKSIZE; psurf_gbl->lPitch = (DWORD)(dwNewWidth * (BitDepth / 8)); // Ddraw surfaces in IA64 have to be DWORD aligned in their // pitch in order for emulation code to work correctly // And on X86 we declared surfaces will be DWORD aligned in // DrvGetDirectDrawInfo (vmiData.dwXXXXXAlign = 4) psurf_gbl->lPitch = MAKE_DWORD_ALIGNED(psurf_gbl->lPitch); psurf_gbl->dwBlockSizeX = (DWORD)((DWORD)dwNewHeight * (DWORD)psurf_gbl->lPitch ); psurf_gbl->dwBlockSizeY = 1; } else { psurf_gbl->lPitch = (DWORD)(psurf_gbl->wWidth * (BitDepth / 8)); // Ddraw surfaces in IA64 have to be DWORD aligned in their // pitch in order for emulation code to work correctly // And on X86 we declared surfaces will be DWORD aligned in // DrvGetDirectDrawInfo (vmiData.dwXXXXXAlign = 4) psurf_gbl->lPitch = MAKE_DWORD_ALIGNED(psurf_gbl->lPitch); #if DX8_3DTEXTURES if (psurf_more->ddsCapsEx.dwCaps2 & DDSCAPS2_VOLUME) { // Put slice pitch into dwBlockSizeY. psurf_gbl->dwBlockSizeY = psurf_gbl->lPitch * psurf_gbl->wHeight; } #endif // DX8_3DTEXTURES } #if DX7_TEXMANAGEMENT // If this is going to be a driver managed texture we'll request DX to // allocate it in a private area in system user memory for us. if (psurf_more->ddsCapsEx.dwCaps2 & DDSCAPS2_TEXTUREMANAGE) { pcsd->lpDDSurfaceDesc->lPitch = psurf_gbl->lPitch; pcsd->lpDDSurfaceDesc->dwFlags |= DDSD_PITCH; if (pcsd->lpDDSurfaceDesc->dwFlags & DDSD_PIXELFORMAT) { pcsd->lpDDSurfaceDesc->lPitch = psurf_gbl->lPitch = ((pcsd->lpDDSurfaceDesc->ddpfPixelFormat.dwRGBBitCount* psurf_gbl->wWidth+31)/32)*4; //make it DWORD aligned // Ddraw surfaces in IA64 have to be DWORD aligned in their // pitch in order for emulation code to work correctly // And on X86 we declared surfaces will be DWORD aligned in // DrvGetDirectDrawInfo (vmiData.dwXXXXXAlign = 4) pcsd->lpDDSurfaceDesc->lPitch = psurf_gbl->lPitch = MAKE_DWORD_ALIGNED(psurf_gbl->lPitch); } #if WNT_DDRAW psurf_gbl->dwUserMemSize = psurf_gbl->lPitch * (DWORD)(psurf_gbl->wHeight); psurf_gbl->fpVidMem = DDHAL_PLEASEALLOC_USERMEM; pcsd->ddRVal = DD_OK; DBG_CB_EXIT(DdCreateSurface, pcsd->ddRVal); return DDHAL_DRIVER_NOTHANDLED; #else // Assume all the memory allocation will succeed if (i == 0) { bHandled = TRUE; } psurf_gbl->fpVidMem = (FLATPTR)HEAP_ALLOC(FL_ZERO_MEMORY, psurf_gbl->lPitch*psurf_gbl->wHeight, ALLOC_TAG_DX(M)); if (psurf_gbl->fpVidMem) { // Move on to the next MIP level, skip calling VRAM allocator continue; } else { pcsd->ddRVal = DDERR_OUTOFMEMORY; DBG_CB_EXIT(DdCreateSurface, pcsd->ddRVal); return DDHAL_DRIVER_HANDLED; } #endif } #endif // DX7_TEXMANAGEMENT // If its not to be created in AGP memory and its not the primary // then we allocate the memory using our videomemory allocator if ((!(psurf->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)) && (!(psurf->ddsCaps.dwCaps & DDSCAPS_NONLOCALVIDMEM))) { P3_MEMREQUEST mmrq; DWORD dwResult; memset(&mmrq, 0, sizeof(P3_MEMREQUEST)); mmrq.dwSize = sizeof(P3_MEMREQUEST); // Compute what size should be requested for the surface allocation #if DX8_3DTEXTURES if (psurf_more->ddsCapsEx.dwCaps2 & DDSCAPS2_VOLUME) { if (bResize) { DISPDBG((ERRLVL,"No volume with block size alloc")); } else { // the depth of volume texture is given in // ddsCapsEx.dwCaps4. mmrq.dwBytes = (DWORD)psurf_gbl->lPitch * (DWORD)psurf_gbl->wHeight * (DWORD)psurf_more->ddsCapsEx.dwCaps4; } } else #endif // DX8_3DTEXTURES { if (bResize) { mmrq.dwBytes = psurf_gbl->dwBlockSizeX * psurf_gbl->dwBlockSizeY; } else { mmrq.dwBytes = (DWORD)psurf_gbl->lPitch * (DWORD)psurf_gbl->wHeight; } } // 16 Byte alignment will work for everything mmrq.dwAlign = 16; // Figure out where in the video mem to place it mmrq.dwFlags = MEM3DL_FIRST_FIT; if(__SUR_bSurfPlacement(psurf, pcsd->lpDDSurfaceDesc) == MEM3DL_FRONT) { mmrq.dwFlags |= MEM3DL_FRONT; } else { mmrq.dwFlags |= MEM3DL_BACK; } DISPDBG((DBGLVL,"DdCreateSurface allocating vidmem for handle #%d", psurf->lpSurfMore->dwSurfaceHandle)); // Try allocating it in our video memory dwResult = _DX_LIN_AllocateLinearMemory( &pThisDisplay->LocalVideoHeap0Info, &mmrq); // Did we got the memory we asked for? if (dwResult != GLDD_SUCCESS) { // If we have an AGP heap and it is a texture request, // don't give up - ask DDRAW to allocate it for us. if ((pThisDisplay->bCanAGP) && ((psurf->ddsCaps.dwCaps & DDSCAPS_TEXTURE ) || (psurf->ddsCaps.dwCaps & DDSCAPS_OFFSCREENPLAIN) )) { DISPDBG((WRNLVL,"No texture VideoMemory left, " "going for AGP")); psurf->ddsCaps.dwCaps &= ~DDSCAPS_LOCALVIDMEM; psurf->ddsCaps.dwCaps |= DDSCAPS_NONLOCALVIDMEM; } else { psurf_gbl->fpVidMem = 0; DISPDBG((ERRLVL, "DdCreateSurface: failed, " "returning NULL")); pcsd->ddRVal = DDERR_OUTOFVIDEOMEMORY; START_SOFTWARE_CURSOR(pThisDisplay); DBG_CB_EXIT(DdCreateSurface, pcsd->ddRVal); return DDHAL_DRIVER_HANDLED; } } else { // We succeeded. Now update the fpVidMem of the surface psurf_gbl->fpVidMem = mmrq.pMem; } } #if WNT_DDRAW // NT requires us to set some things up differently pcsd->lpDDSurfaceDesc->lPitch = psurf_gbl->lPitch; pcsd->lpDDSurfaceDesc->dwFlags |= DDSD_PITCH; #endif // Mark the surface with the correct video memory type if (psurf->ddsCaps.dwCaps & DDSCAPS_NONLOCALVIDMEM) { DISPDBG((DBGLVL,"Surface is in AGP memory")); ASSERTDD(pThisDisplay->bCanAGP, "** DdCreateSurface: Somehow managed to create an AGP " "texture when AGP disabled" ); psurf->ddsCaps.dwCaps &= ~DDSCAPS_LOCALVIDMEM; psurf->ddsCaps.dwCaps |= DDSCAPS_NONLOCALVIDMEM; // let DDraw manage AGP memory (return DDHAL_DRIVER_NOTHANDLED) // THIS IS ABSOLUTELY NECESSARY IF WE WANT DDRAW TO ALLOCTE THIS! bHandled = FALSE; } else { DISPDBG((DBGLVL,"Surface in Local Video Memory")); psurf->ddsCaps.dwCaps &= ~DDSCAPS_NONLOCALVIDMEM; psurf->ddsCaps.dwCaps |= DDSCAPS_LOCALVIDMEM; } DISPDBG((DBGLVL, "DdCreateSurface: Surface=0x%08x, vidMem=0x%08x", psurf, psurf_gbl->fpVidMem)); } // for i START_SOFTWARE_CURSOR(pThisDisplay); // // If we allocated the memory successfully then we return OK and // say that we handled it. Otherwise we should return DDHAL_DRIVER_NOTHANDLED // if(bHandled) { pcsd->ddRVal = DD_OK; DBG_CB_EXIT(DdCreateSurface, pcsd->ddRVal); return DDHAL_DRIVER_HANDLED; } else { // if we return handled, then it is assumed that we did SOMETHING // with the surface structures to indicate either what size of block // or a new pitch or some modification; or we are returning an error. DBG_CB_EXIT(DdCreateSurface, pcsd->ddRVal); return DDHAL_DRIVER_NOTHANDLED; } } // DdCreateSurface //-----------------------------Public Routine---------------------------------- // // DdDestroySurface // // Destroys a DirectDraw surface. // // If DirectDraw did the memory allocation at surface creation time, // DdDestroySurface should return DDHAL_DRIVER_NOTHANDLED. // // If the driver is performing the surface memory management itself, // DdDestroySurface should free the surface memory and perform any other // cleanup, such as freeing private data stored in the dwReserved1 members // of the DD_SURFACE_GLOBAL and DD_SURFACE_LOCAL structures. // // Parameters // // psdd // Points to a DD_DESTROYSURFACEDATA structure that contains the // information needed to destroy a surface. // // .lpDD // Points to the DD_DIRECTDRAW_GLOBAL structure that describes // the driver. // .lpDDSurface // Points to the DD_SURFACE_LOCAL structure representing the // surface object to be destroyed. // .ddRVal // Specifies the location in which the driver writes the return // value of the DdDestroySurface callback. A return code of // DD_OK indicates success. // .DestroySurface // This is unused on Windows 2000. // //----------------------------------------------------------------------------- DWORD CALLBACK DdDestroySurface( LPDDHAL_DESTROYSURFACEDATA psdd ) { P3_THUNKEDDATA* pThisDisplay; DBG_CB_ENTRY(DdDestroySurface); GET_THUNKEDDATA(pThisDisplay, psdd->lpDD); // make sure the DMA buffer is flushed and // complete before we destroy any surface STOP_SOFTWARE_CURSOR(pThisDisplay); { P3_DMA_DEFS(); DDRAW_OPERATION(pContext, pThisDisplay); P3_DMA_GET_BUFFER(); P3_DMA_FLUSH_BUFFER(); WAIT_DMA_COMPLETE; } START_SOFTWARE_CURSOR(pThisDisplay); DISPDBG((DBGLVL,"DdDestroySurface handle # %d", psdd->lpDDSurface->lpSurfMore->dwSurfaceHandle)); // If we are destroying a videomemory surface which isn't the primary, // we'll need to free ourselves the memory as the driver is managing // its own local video memory (though non-local/AGP memory is being // managed by DirectDraw) if ((!(psdd->lpDDSurface->ddsCaps.dwCaps & DDSCAPS_NONLOCALVIDMEM)) && (!(psdd->lpDDSurface->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE))) { #if DX7_TEXMANAGEMENT // If this is a driver managed texture surface, we need to make sure // it is deallocated from video memory before proceeding. if (psdd->lpDDSurface->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_TEXTUREMANAGE) { if (psdd->lpDDSurface->dwFlags & DDRAWISURF_INVALID) { // This is not a surface destruction, // but a managed surface eviction #if W95_DDRAW // On Win2k, managed textures are evicted from video memory by // _DD_TM_EvictAllManagedTextures() when mode change happens. _D3D_TM_RemoveDDSurface(pThisDisplay, psdd->lpDDSurface); #endif psdd->ddRVal= DD_OK; DBG_CB_EXIT(DdDestroySurface, psdd->ddRVal); return DDHAL_DRIVER_HANDLED; } else { // Normal destruction of managed surface _D3D_TM_RemoveDDSurface(pThisDisplay, psdd->lpDDSurface); #if W95_DDRAW // On Win2k, runtime will free the system memory for drivers. if (psdd->lpDDSurface->lpGbl->fpVidMem) { HEAP_FREE((LPVOID)psdd->lpDDSurface->lpGbl->fpVidMem); } #endif } } else #endif { // Have no memory to free in error recovery case if (psdd->lpDDSurface->lpGbl->fpVidMem) { _DX_LIN_FreeLinearMemory(&pThisDisplay->LocalVideoHeap0Info, (DWORD)(psdd->lpDDSurface->lpGbl->fpVidMem)); } } // Must reset the surface pointer to NULL DISPDBG((DBGLVL, "DdDestroySurface: setting ptr to NULL")); psdd->lpDDSurface->lpGbl->fpVidMem = 0; psdd->lpDDSurface->lpGbl->dwReserved1 = 0; psdd->ddRVal = DD_OK; DBG_CB_EXIT(DdDestroySurface, psdd->ddRVal); return DDHAL_DRIVER_HANDLED; } else { DISPDBG((WRNLVL, "DdDestroySurface: **NOT** setting ptr to NULL")); psdd->lpDDSurface->lpGbl->dwReserved1 = 0; psdd->ddRVal = DD_OK; DBG_CB_EXIT(DdDestroySurface, psdd->ddRVal); return DDHAL_DRIVER_NOTHANDLED; } } // DdDestroySurface //-----------------------------Public Routine---------------------------------- // // DdSetColorKey // // Sets the color key value for the specified surface. // // DdSetColorKey sets the source or destination color key for the specified // surface. Typically, this callback is implemented only for drivers that // support overlays with color key capabilities. // // Parameters // // psckd // Points to a DD_SETCOLORKEYDATA structure that contains the // information required to set the color key for the specified surface. // // .lpDD // Points to the DD_DIRECTDRAW_GLOBAL structure that describes // the driver. // .lpDDSurface // Points to the DD_SURFACE_LOCAL structure that describes the // surface with which the color key is to be associated. // .dwFlags // Specifies which color key is being requested. This member is // a bit-wise OR of any of the following values: // // DDCKEY_COLORSPACE // The DDCOLORKEY structure contains a color space. If // this bit is not set, the structure contains a single // color key. // DDCKEY_DESTBLT // The DDCOLORKEY structure specifies a color key or color // space to be used as a destination color key for blit // operations. // DDCKEY_DESTOVERLAY // The DDCOLORKEY structure specifies a color key or color // space to be used as a destination color key for overlay // operations. // DDCKEY_SRCBLT // The DDCOLORKEY structure specifies a color key or color // space to be used as a source color key for blit // operations. // DDCKEY_SRCOVERLAY // The DDCOLORKEY structure specifies a color key or color // space to be used as a source color key for overlay // operations. // .ckNew // Specifies a DDCOLORKEY structure that specifies the new color // key values for the DirectDrawSurface object. // .ddRVal // Specifies the location in which the driver writes the return // value of the DdSetColorKey callback. A return code of DD_OK // indicates success. // .SetColorKey // This is not used on Windows 2000. // //----------------------------------------------------------------------------- DWORD CALLBACK DdSetColorKey( LPDDHAL_SETCOLORKEYDATA psckd) { P3_THUNKEDDATA* pThisDisplay; DBG_CB_ENTRY(DdSetColorKey); GET_THUNKEDDATA(pThisDisplay, psckd->lpDD); //@@BEGIN_DDKSPLIT #if 0 // Also, see if this colour key is the one used by the overlay. // Yes, we should check that various surfaces agree and so on, // but can we assume apps are not going to set these flags if there is // no overlay active/appropriate? if ( psckd->dwFlags & DDCKEY_DESTOVERLAY ) { pThisDisplay->OverlayDstColourKey = psckd->ckNew.dwColorSpaceLowValue; } #endif //@@END_DDKSPLIT // We have to keep track of colorkey changes for D3D videomemory textures // associated with (some) D3D context. We don't know however from this call // which D3D context this is so we have to do a search through them (if // there are any at all) if ((DDSCAPS_TEXTURE & psckd->lpDDSurface->ddsCaps.dwCaps) && (DDSCAPS_VIDEOMEMORY & psckd->lpDDSurface->ddsCaps.dwCaps) && (pThisDisplay->pDirectDrawLocalsHashTable != NULL)) { DWORD dwSurfaceHandle = psckd->lpDDSurface->lpSurfMore->dwSurfaceHandle; PointerArray* pSurfaceArray; // For now we'll assume failure unless proven otherwise psckd->ddRVal = DDERR_INVALIDPARAMS; // Get a pointer to an array of surface pointers associated to this lpDD // The PDD_DIRECTDRAW_LOCAL was stored at D3DCreateSurfaceEx call time // in PDD_SURFACE_LOCAL->dwReserved1 pSurfaceArray = (PointerArray*) HT_GetEntry(pThisDisplay->pDirectDrawLocalsHashTable, psckd->lpDDSurface->dwReserved1); if (pSurfaceArray) { // Found a surface array associated to this lpDD ! P3_SURF_INTERNAL* pSurfInternal; // Check the surface in this array associated to this surface handle pSurfInternal = PA_GetEntry(pSurfaceArray, dwSurfaceHandle); if (pSurfInternal) { // Got it! Now update the color key setting(s) pSurfInternal->dwFlagsInt |= DDRAWISURF_HASCKEYSRCBLT; pSurfInternal->dwCKLow = psckd->ckNew.dwColorSpaceLowValue; pSurfInternal->dwCKHigh = psckd->ckNew.dwColorSpaceHighValue; // Report success! psckd->ddRVal = DD_OK; } } } else { // No D3D colorkey tracking necessary psckd->ddRVal = DD_OK; } DBG_CB_EXIT(DdSetColorKey, psckd->ddRVal); return DDHAL_DRIVER_HANDLED; } // DdSetColorKey //-----------------------------Public Routine---------------------------------- // // DdGetAvailDriverMemory // // DdGetAvailDriverMemory queries the amount of free memory in the driver // managed memory heap. This function does not need to be implemented if the // memory will be managed by DirectDraw. // // DdGetAvailDriverMemory determines how much free memory is in the driver's // private heaps for the specified surface type. The driver should check the // surface capabilities specified in DDSCaps against the heaps that it is // maintaining internally to determine which heap size to query. For example, // if DDSCAPS_NONLOCALVIDMEM is set, the driver should return only // contributions from the AGP heaps. // // The driver indicates its support of DdGetAvailDriverMemory by implementing a // response to GUID_MiscellaneousCallbacks in DdGetDriverInfo. // // Parameters // // pgadmd // Points to a DD_GETAVAILDRIVERMEMORYDATA structure that contains the // information required to perform the query. // // lpDD // Points to the DD_DIRECTDRAW_GLOBAL structure that describes // the driver. // DDSCaps // Points to a DDSCAPS structure that describes the type of // surface for which memory availability is being queried. // The DDSCAPS structure is defined in ddraw.h. // dwTotal // Specifies the location in which the driver returns the // number of bytes of driver-managed memory that can be used // for surfaces of the type described by DDSCaps. // dwFree // Specifies the location in which the driver returns the // amount of free memory, in bytes, for the surface type // described by DDSCaps. // ddRVal // Specifies the location in which the driver writes the // return value of the DdGetAvailDriverMemory callback. A // return code of DD_OK indicates success. // GetAvailDriverMemory // This is unused on Windows 2000. // // Return Value // DdGetAvailDriverMemory returns one of the following callback codes: // // DDHAL_DRIVER_HANDLED // DDHAL_DRIVER_NOTHANDLED // // Comments // // DdGetAvailDriverMemory determines how much free memory is in the // driver's private heaps for the specified surface type. The driver // should check the surface capabilities specified in DDSCaps against // the heaps that it is maintaining internally to determine which heap // size to query. For example, if DDSCAPS_NONLOCALVIDMEM is set, the // driver should return only contributions from the AGP heaps. // //----------------------------------------------------------------------------- DWORD CALLBACK DdGetAvailDriverMemory( LPDDHAL_GETAVAILDRIVERMEMORYDATA pgadmd) { P3_THUNKEDDATA* pThisDisplay; DBG_CB_ENTRY(DdGetAvailDriverMemory); GET_THUNKEDDATA(pThisDisplay, pgadmd->lpDD); VALIDATE_MODE_AND_STATE(pThisDisplay); DISPDBG((DBGLVL, "Heap0: dwMemStart:0x%x, dwMemEnd:0x%x", pThisDisplay->LocalVideoHeap0Info.dwMemStart, pThisDisplay->LocalVideoHeap0Info.dwMemEnd)); pgadmd->ddRVal = DD_OK; if (pgadmd->DDSCaps.dwCaps & DDSCAPS_NONLOCALVIDMEM) { DISPDBG((DBGLVL," Not returning AGP heap free memory " "(we don't manage it)")); DBG_CB_EXIT(DdGetAvailDriverMemory, pgadmd->ddRVal); return DDHAL_DRIVER_NOTHANDLED; } else { pgadmd->dwTotal = pThisDisplay->LocalVideoHeap0Info.dwMaxChunks * pThisDisplay->LocalVideoHeap0Info.dwMemPerChunk; pgadmd->dwFree = _DX_LIN_GetFreeMemInHeap(&pThisDisplay->LocalVideoHeap0Info); } DISPDBG((DBGLVL," Returning %d TotalMem, of which %d free", pgadmd->dwTotal, pgadmd->dwFree)); DBG_CB_EXIT(DdGetAvailDriverMemory, pgadmd->ddRVal); return DDHAL_DRIVER_HANDLED; } // DdGetAvailDriverMemory #if W95_DDRAW //----------------------------------------------------------------------------- // // __FindAGPHeap // //----------------------------------------------------------------------------- static void __FindAGPHeap( P3_THUNKEDDATA* pThisDisplay, LPDDRAWI_DIRECTDRAW_GBL lpDD ) { VIDMEMINFO MemInfo = lpDD->vmiData; LPVIDMEM pStartHeap; LPVIDMEM pCurrentHeap = NULL; BOOL bFoundAGPHeap = FALSE; if ((pThisDisplay->bCanAGP) && (pThisDisplay->dwGARTDev != 0) && (MemInfo.dwNumHeaps) && (MemInfo.pvmList)) { int i; // Look around for a good AGP heap pStartHeap = MemInfo.pvmList; for (i = 0; i < (int)MemInfo.dwNumHeaps; i++) { pCurrentHeap = pStartHeap + i; if (pCurrentHeap->dwFlags & VIDMEM_ISNONLOCAL) { bFoundAGPHeap = TRUE; break; } } } else { DISPDBG((ERRLVL,"Unable to allocate AGP memory (AllocatePrivAGPMem)")); } if(!bFoundAGPHeap) { DISPDBG((ERRLVL,"Unable to locate AGP heap (AllocatePrivAGPMem)")); } pThisDisplay->pAGPHeap = pCurrentHeap; } // __FindAGPHeap //-----------------------------Public Routine---------------------------------- // DdUpdateNonLocalHeap // // Received the address of the AGP Heap and updates the chip. // // //----------------------------------------------------------------------------- DWORD CALLBACK DdUpdateNonLocalHeap( LPDDHAL_UPDATENONLOCALHEAPDATA plhd) { P3_THUNKEDDATA* pThisDisplay; GET_THUNKEDDATA(pThisDisplay, plhd->lpDD); DISPDBG((DBGLVL,"** In DdUpdateNonLocalHeap - for Heap 0x%x", plhd->dwHeap)); // Fill in the base pointers pThisDisplay->dwGARTDevBase = (DWORD)plhd->fpGARTDev; pThisDisplay->dwGARTLinBase = (DWORD)plhd->fpGARTLin; // Fill in the changeable base pointers. pThisDisplay->dwGARTDev = pThisDisplay->dwGARTDevBase; pThisDisplay->dwGARTLin = pThisDisplay->dwGARTLinBase; __FindAGPHeap( pThisDisplay, plhd->lpDD ); DISPDBG((DBGLVL,"GartLin: 0x%x, GartDev: 0x%x", plhd->fpGARTLin, plhd->fpGARTDev)); plhd->ddRVal = DD_OK; return DDHAL_DRIVER_HANDLED; } // DdUpdateNonLocalHeap() //-----------------------------Public Routine---------------------------------- // // DdGetHeapAlignment // //----------------------------------------------------------------------------- DWORD CALLBACK DdGetHeapAlignment( LPDDHAL_GETHEAPALIGNMENTDATA lpGhaData) { P3_THUNKEDDATA* pThisDisplay; DISPDBG(( DBGLVL,"DdGetHeapAlignment: Heap %d", lpGhaData->dwHeap )); if (lpGhaData->dwInstance) pThisDisplay = (P3_THUNKEDDATA*)lpGhaData->dwInstance; else pThisDisplay = (P3_THUNKEDDATA*)g_pDriverData; if( lpGhaData->dwHeap <= 2 ) { lpGhaData->Alignment.ddsCaps.dwCaps = DDSCAPS_TEXTURE; lpGhaData->Alignment.Texture.Linear.dwStartAlignment = 16; lpGhaData->ddRVal = DD_OK; return DDHAL_DRIVER_HANDLED; } else { lpGhaData->ddRVal = DDERR_INVALIDPARAMS; return DDHAL_DRIVER_NOTHANDLED; } } // DdGetHeapAlignment #endif // W95_DDRAW