D3dCreateSurfaceEx routine

The D3dCreateSurfaceEx function notifies about the association of a Microsoft DirectDraw surface and a Microsoft Direct3D handle value to enable setting up the surface for Direct3D rendering.



DWORD D3dCreateSurfaceEx(
{ ... }



Points to a DD_CREATESURFACEEXDATA structure that contains the information required for the driver to create the surface.

Return value

D3dCreateSurfaceEx returns one of the following callback codes:



All Direct3D drivers must support D3dCreateSurfaceEx.

D3dCreateSurfaceEx creates an association between a DirectDraw surface and a small integer surface handle. By creating these associations between a handle and a DirectDraw surface, D3dCreateSurfaceEx allows a surface handle to be embedded in the Direct3D command stream. For example, when the D3DDP2OP_TEXBLT command token is sent to the driver's D3dDrawPrimitives2 function to load a texture map, it uses a source handle and destination handle that were associated with a DirectDraw surface through D3dCreateSurfaceEx.

For every DirectDraw surface created under the local DirectDraw object, the runtime generates a valid handle that uniquely identifies the surface and places the handle in the dwSurfaceHandle member of a DD_SURFACE_MORE structure. The lpDDSLcl member of the DD_CREATESURFACEEXDATA structure at pcsxd points to a DD_SURFACE_LOCAL structure that contains a lpSurfMore member that points to this DD_SURFACE_MORE. This handle value is also used with the D3DRENDERSTATE_TEXTUREHANDLE render state to enable texturing, and with the D3DDP2OP_SETRENDERTARGET and D3DDP2OP_CLEAR commands to set and clear new rendering and depth buffers. The driver should fail the call and return DDHAL_DRIVER_HANDLED if it cannot create the Direct3D surface.

For either a system memory surface or video memory surface, when D3dCreateSurfaceEx is called to notify about the association of dwSurfaceHandle with the surface's DD_SURFACE_GLOBAL and DD_SURFACE_LOCAL structures, the display driver can store any data (for example, a pointer to privately allocated memory) in the dwReserved1 members of DD_SURFACE_GLOBAL and DD_SURFACE_LOCAL because these members are reserved for private use by the display driver.

To notify the display driver that a system memory surface is to be released, the runtime sets the fpVidMem pointer member of the system memory surface's DD_SURFACE_GLOBAL structure to zero and calls the display driver's D3dCreateSurfaceEx callback. In addition to releasing all resources associated with this surface, the display driver must clear out the data that was previously stored in the dwReserved1 members. Note that because the fpVidMem pointer member for a video memory surface can be set to zero, the display driver must verify whether the surface is in video or system memory to determine if the call to D3dCreateSurfaceEx is meant to notify about the association of a video memory surface with dwSurfaceHandle or to notify about the disassociation of a system memory surface from dwSurfaceHandle.

D3dCreateSurfaceEx is not called to notify about the disassociation of a video memory surface from dwSurfaceHandle; the display driver's DdDestroySurface callback must handle local and nonlocal video memory surface deletion and must clear out data that was previously stored in the dwReserved1 members.

The driver should also store any surface-related information that it needs when using the surface. The driver must create a new surface table for each new lpDDLcl and implicitly enlarge the table when necessary to accommodate more surfaces. Typically, this is done with an exponential growth algorithm so that you do not have to enlarge the table too often. See the Perm3 sample driver that was included with the Microsoft Windows Driver Development Kit (DDK) for implementation details. (The DDK preceded the Windows Driver Kit [WDK].)

Note   The Microsoft Windows Driver Kit (WDK) does not contain the 3Dlabs Permedia3 (Perm3.htm) sample display driver. You can get this sample driver from the Windows Server 2003 SP1 DDK, which you can download from the DDK - Windows Driver Development Kit page of the WDHC website.

Direct3D calls D3dCreateSurfaceEx after the surface is created by DirectDraw by request of the Direct3D runtime or the application.

D3dCreateSurfaceEx can only be called with a disabled PDEV for a system memory surface. A PDEV is disabled or enabled by calling the display driver's DrvAssertMode function. See Managing PDEVs for more information.

Sample implementation of D3dCreateSurfaceEx

    DDSCAPS2 * pddsCaps2)
    pAl = pLcl->lpAttachList;
    while (pAl) {
        LPDDRAWI_DDRAWSURFACE_LCL pLclAttached = pAl->lpAttached;
        LPATTACHLIST pAlAttached = pLclAttached->lpAttachList;
        if ((pLclAttached->lpSurfMore->ddsCapsEx.dwCaps2 & pddsCaps2->dwCaps2) ||
            (pLclAttached->lpSurfMore->ddsCapsEx.dwCaps3 & pddsCaps2->dwCaps3) ||
            (pLclAttached->lpSurfMore->ddsCapsEx.dwCaps4 & pddsCaps2->dwCaps4) ||
            (pLclAttached->ddsCaps.dwCaps & pddsCaps2->dwCaps)
            return pLclAttached;
        pAl = pAl->lpLink;
    return NULL;
void CSExProcessPossibleMipmap(LPDDRAWI_DDRAWSURFACE_LCL pLcl)
    // A more likely scenario would be to build a list of surfaces
    // so that the driver can create one structure that represents the
    // entire mipmap, rather than creating an object to represent each
    // level as depicted here.
    while (pLcl) {
        //Call the private driver routine that creates a driver-side surface structure
        pLcl = GetAttachedSurface(pLcl,&ddsCaps2);

// The actual return type should reflect the fact that the only
// way this routine should fail is with DDERR_OUTOFMEMORY
void MyCreateSurfaceExHelper(LPDDRAWI_DDRAWSURFACE_LCL pLcl)
    DDSCAPS2 ddsCaps2 = {0,0,0,0};
    if (pLcl->lpGbl->fpVidMem == 0) {
        //A required check against bad surfaces
        if (pLcl->ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY)
        //Else, this is a system memory surface, so we are being informed of
        // its destruction
    if (pLcl->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_CUBEMAP) {
        int i;
        // The root surface is always positive X, so we check for the
        // other five face types.
        DWORD dw[5] = {
        for(i=0;i< sizeof(dw)/sizeof(dw[0]);i++) {
            ddsCaps2.dwCaps2 = dw[i];
            pLclAttached = GetAttachedSurface(pLcl, &ddsCaps2);
            if (pLclAttached)
        // Once we know it's a cube map, we know there cannot be any other 
        // attachments.
    // At this point:
    //      If it's a cubemap, we returned above.
    //      If it's a mipmap, we handled all cases above.
    // The only other complex surface possibility is a primary flipping chain.
    // Because a primary flipping chain cannot be mipmapped, we will simply return
    // here if this surface is a mipmap.
    if (pLcl->ddsCaps.dwCaps & DDSCAPS_MIPMAP)
    // The only system memory surfaces we'll ever be interested in are textures (mipmaps)
    // and cube maps.   We do not propagate an error code for system memory
    // surfaces whose format we do not understand. This could cause an error code to 
    // be propagated to the application when it was trying to use system memory surfaces
    // of a format we do not understand, but is valid for the reference rasterizer, for example.
    if (pLcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
    // Now walk around a flipping chain. A flipping chain is a ring of
    // surfaces attached to each other (each surface is attached to the next
    // and to the previous surface in the ring, but not to any other surface
    // in the ring).
    // We need to watch out for this circular ring and make sure we exit appropriately.
    // There is also the possibility of a z buffer attached to one of the surfaces
    // in the ring, which may or may not have been CreateSurfaceEx'ed already.
    pLclStart = pLcl;
    while (pLcl && pLcl != pLclStart) {
        //Check for Z buffer attached to this surface in the ring.
        ddsCaps2.dwCaps = DDSCAPS_ZBUFFER;
        ddsCaps2.dwCaps2 = 0;
        pLclAttached = GetAttachedSurface(pLcl, &ddsCaps2);
        if (pLclAttached)
        //Check for stereo left surface attached to this surface in the ring
        ddsCaps2.dwCaps = 0;
        ddsCaps2.dwCaps2 = DDSCAPS2_STEREOSURFACELEFT;
        pLclAttached = GetAttachedSurface(pLcl, &ddsCaps2);
        if (pLclAttached)
        // Move to next surface in the primary flipping ring. The next surface is 
        // definitely in video memory (all surfaces in an attachment structure have
        // to be in the same memory type, and we excluded system memory above).
        // The next surface in the ring is thus the attached video memory surface
        // that is NOT a z buffer NOR a stereo left surface.
        ddsCaps2.dwCaps = DDSCAPS_VIDEOMEMORY;
        ddsCaps2.dwCaps2 = 0;
        do {
            pLclAttached = GetAttachedSurface(pLcl, &ddsCaps2);
        while (
            pLclAttached->ddsCaps.dwCaps & DDSCAPS_ZBUFFER ||
            pLclAttached->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_STEREOSURFACELEFT
        pLcl = pLclAttached;
        if (pLcl != pLclStart)


Target platform


Ddrawint.h (include Winddi.h)

See also




Send comments about this topic to Microsoft