static BOOL CreateDrawArea(PDev *pdev, UINT8 *base_mem, ULONG format, UINT32 cx, UINT32 cy, UINT32 stride, UINT32 surface_id) { SIZEL size; DrawArea *drawarea; size.cx = cx; size.cy = cy; drawarea = &GetSurfaceInfo(pdev, surface_id)->draw_area; if (!(drawarea->bitmap = (HSURF)EngCreateBitmap(size, stride, format, 0, base_mem))) { DEBUG_PRINT((pdev, 0, "%s: EngCreateBitmap failed\n", __FUNCTION__)); return FALSE; } if (!EngAssociateSurface(drawarea->bitmap, pdev->eng, 0)) { DEBUG_PRINT((pdev, 0, "%s: EngAssociateSurface failed\n", __FUNCTION__)); goto error; } if (!(drawarea->surf_obj = EngLockSurface(drawarea->bitmap))) { DEBUG_PRINT((pdev, 0, "%s: EngLockSurface failed\n", __FUNCTION__)); goto error; } drawarea->base_mem = base_mem; return TRUE; error: EngDeleteSurface(drawarea->bitmap); return FALSE; }
HBITMAP CreateDeviceBitmap(PDev *pdev, SIZEL size, ULONG format, QXLPHYSICAL *phys_mem, UINT8 **base_mem, UINT32 surface_id, UINT8 allocation_type) { UINT32 surface_format, depth; HBITMAP hbitmap; INT32 stride; SurfaceInfo *surface_info; DEBUG_PRINT((pdev, 9, "%s: %p: %d, (%dx%d), %d\n", __FUNCTION__, pdev, surface_id, size.cx, size.cy, format)); surface_info = GetSurfaceInfo(pdev, surface_id); if (!(hbitmap = EngCreateDeviceBitmap((DHSURF)surface_info, size, format))) { DEBUG_PRINT((pdev, 0, "%s: EngCreateDeviceBitmap failed, pdev 0x%lx, surface_id=%d\n", __FUNCTION__, pdev, surface_id)); goto out_error1; } if (!EngAssociateSurface((HSURF)hbitmap, pdev->eng, QXL_SURFACE_HOOKS)) { DEBUG_PRINT((pdev, 0, "%s: EngAssociateSurface failed\n", __FUNCTION__)); goto out_error2; } surface_info->u.pdev = pdev; surface_info->hbitmap = hbitmap; surface_info->copy = NULL; surface_info->size = size; surface_info->bitmap_format = format; if ((*base_mem = CreateSurfaceHelper(pdev, surface_id, size.cx, size.cy, format, allocation_type, &stride, &surface_format, phys_mem)) == NULL) { DEBUG_PRINT((pdev, 0, "%s: failed, pdev 0x%lx, surface_id=%d\n", __FUNCTION__, pdev, surface_id)); goto out_error2; } surface_info->stride = stride; if (allocation_type != DEVICE_BITMAP_ALLOCATION_TYPE_SURF0) { SendSurfaceCreateCommand(pdev, surface_id, size, surface_format, -stride, *phys_mem, 0); } return hbitmap; out_error2: EngDeleteSurface((HSURF)hbitmap); out_error1: return 0; }
HSURF DrvEnableSurface(DHPDEV dhpdev) { LPFAXDEV lpFaxDev = (LPFAXDEV)dhpdev; HBITMAP hbm = 0; LOGDEBUG(("WOWFAX!DrvEnableSurface, lpFaxDev: %X\n", lpFaxDev)); if (ValidateFaxDev(lpFaxDev)) { // GDI will allocate space for the bitmap bits. We'll use a DrvEscape // to copy them to the client side. hbm = EngCreateBitmap(lpFaxDev->gdiinfo.szlPhysSize, lpFaxDev->bmWidthBytes, lpFaxDev->bmFormat, BMF_TOPDOWN, NULL); if (hbm) { lpFaxDev->hbm = hbm; EngAssociateSurface((HSURF)hbm, lpFaxDev->hdev, 0); return (HSURF)hbm; } LOGDEBUG(("WOWFAX!DrvEnableSurface, EngCreateBitmap failed\n")); } return (HSURF)hbm; }
HSURF DrvEnableSurface( DHPDEV dhpdev) { PPDEV ppdev; HSURF hsurf; SIZEL sizl; ULONG ulBitmapType; FLONG flHooks; // Create engine bitmap around frame buffer. ppdev = (PPDEV) dhpdev; if (!bInitSURF(ppdev, TRUE)) { RIP("DISP DrvEnableSurface failed bInitSURF\n"); return(FALSE); } sizl.cx = ppdev->cxScreen; sizl.cy = ppdev->cyScreen; if (ppdev->ulBitCount == 8) { if (!bInit256ColorPalette(ppdev)) { RIP("DISP DrvEnableSurface failed to init the 8bpp palette\n"); return(FALSE); } ulBitmapType = BMF_8BPP; flHooks = HOOKS_BMF8BPP; } else if (ppdev->ulBitCount == 16) { ulBitmapType = BMF_16BPP; flHooks = HOOKS_BMF16BPP; } else if (ppdev->ulBitCount == 24) { ulBitmapType = BMF_24BPP; flHooks = HOOKS_BMF24BPP; } else { ulBitmapType = BMF_32BPP; flHooks = HOOKS_BMF32BPP; } hsurf = (HSURF) EngCreateBitmap(sizl, ppdev->lDeltaScreen, ulBitmapType, (ppdev->lDeltaScreen > 0) ? BMF_TOPDOWN : 0, (PVOID) (ppdev->pjScreen)); if (hsurf == (HSURF) 0) { RIP("DISP DrvEnableSurface failed EngCreateBitmap\n"); return(FALSE); } if (!EngAssociateSurface(hsurf, ppdev->hdevEng, flHooks)) { RIP("DISP DrvEnableSurface failed EngAssociateSurface\n"); EngDeleteSurface(hsurf); return(FALSE); } ppdev->hsurfEng = hsurf; return(hsurf); }
/* Called to reset device to default mode or to mode specified with dhpdev */ BOOL APIENTRY VBoxDispDrvAssertMode(DHPDEV dhpdev, BOOL bEnable) { PVBOXDISPDEV pDev = (PVBOXDISPDEV) dhpdev; DWORD dwrc; int rc; LOGF_ENTER(); if (!bEnable) { LOGF(("!bEnable")); #ifdef VBOX_WITH_VIDEOHWACCEL /* tells we can not process host commands any more and ensures that * we've completed processing of the host VHWA commands */ VBoxDispVHWADisable(pDev); #endif /* disable VBVA */ if (pDev->hgsmi.bSupported) { VBoxVBVADisable(&pDev->vbvaCtx, &pDev->hgsmi.ctx, -1); } /* reset the device to default mode */ rc = VBoxDispMPResetDevice(pDev->hDriver); VBOX_WARNRC_RETV(rc, FALSE); } else { LOGF(("bEnable")); /* switch device to previous pDev mode */ rc = VBoxDispMPSetCurrentMode(pDev->hDriver, pDev->mode.ulIndex); VBOX_WARNRC_RETV(rc, NULL); /* enable VBVA */ if (pDev->hgsmi.bSupported) { if (pDev->mode.ulBitsPerPel==16 || pDev->mode.ulBitsPerPel==24 || pDev->mode.ulBitsPerPel==32) { VBVABUFFER *pVBVA = (VBVABUFFER *)((uint8_t *)pDev->memInfo.VideoRamBase+pDev->layout.offVBVABuffer); pDev->hgsmi.bSupported = VBoxVBVAEnable(&pDev->vbvaCtx, &pDev->hgsmi.ctx, pVBVA, -1); LogRel(("VBoxDisp[%d]: VBVA %senabled\n", pDev->iDevice, pDev->hgsmi.bSupported? "":"not ")); } } /* inform host */ if (pDev->hgsmi.bSupported) { VBoxHGSMIProcessDisplayInfo(&pDev->hgsmi.ctx, pDev->iDevice, pDev->orgDev.x, pDev->orgDev.y, 0, abs(pDev->mode.lScanlineStride), pDev->mode.ulWidth, pDev->mode.ulHeight, (uint16_t)pDev->mode.ulBitsPerPel, VBVA_SCREEN_F_ACTIVE); } #ifdef VBOX_WITH_VIDEOHWACCEL /* tells we can process host commands */ VBoxDispVHWAEnable(pDev); #endif /* Associate back GDI bitmap residing in our framebuffer memory with GDI's handle to our device */ dwrc = EngAssociateSurface((HSURF)pDev->surface.hBitmap, pDev->hDevGDI, 0); if (dwrc != NO_ERROR) { WARN(("EngAssociateSurface on bitmap failed with %#x", dwrc)); return FALSE; } /* Associate device managed surface with GDI's handle to our device */ dwrc = EngAssociateSurface(pDev->surface.hSurface, pDev->hDevGDI, pDev->flDrawingHooks); if (dwrc != NO_ERROR) { WARN(("EngAssociateSurface on surface failed with %#x", dwrc)); return FALSE; } } LOGF_LEAVE(); return TRUE; }
/* Called to create and associate surface with device */ HSURF APIENTRY VBoxDispDrvEnableSurface(DHPDEV dhpdev) { int rc; PVBOXDISPDEV pDev = (PVBOXDISPDEV)dhpdev; LOGF_ENTER(); /* Switch device to mode requested in VBoxDispDrvEnablePDEV */ rc = VBoxDispMPSetCurrentMode(pDev->hDriver, pDev->mode.ulIndex); VBOX_WARNRC_RETV(rc, NULL); /* Map fb and vram */ rc = VBoxDispMPMapMemory(pDev, &pDev->memInfo); VBOX_WARNRC_RETV(rc, NULL); /* Clear mapped memory, to avoid garbage while video mode is switching */ /* @todo: VIDEO_MODE_NO_ZERO_MEMORY does nothing in miniport's IOCTL_VIDEO_SET_CURRENT_MODE*/ memset(pDev->memInfo.FrameBufferBase, 0, pDev->mode.ulHeight * abs(pDev->mode.lScanlineStride)); /* Allocate memory for pointer attrs */ rc = VBoxDispInitPointerAttrs(pDev); VBOX_WARNRC_RETV(rc, NULL); /* Init VBVA */ rc = VBoxDispVBVAInit(pDev); VBOX_WARNRC_RETV(rc, NULL); /* Enable VBVA */ if (pDev->hgsmi.bSupported) { if (pDev->mode.ulBitsPerPel==16 || pDev->mode.ulBitsPerPel==24 || pDev->mode.ulBitsPerPel==32) { VBVABUFFER *pVBVA = (VBVABUFFER *)((uint8_t *)pDev->memInfo.VideoRamBase+pDev->layout.offVBVABuffer); pDev->hgsmi.bSupported = VBoxVBVAEnable(&pDev->vbvaCtx, &pDev->hgsmi.ctx, pVBVA, -1); LogRel(("VBoxDisp[%d]: VBVA %senabled\n", pDev->iDevice, pDev->hgsmi.bSupported? "":"not ")); } } /* Inform host */ if (pDev->hgsmi.bSupported) { VBoxHGSMIProcessDisplayInfo(&pDev->hgsmi.ctx, pDev->iDevice, pDev->orgDev.x, pDev->orgDev.y, 0, abs(pDev->mode.lScanlineStride), pDev->mode.ulWidth, pDev->mode.ulHeight, (uint16_t)pDev->mode.ulBitsPerPel, VBVA_SCREEN_F_ACTIVE); } #ifdef VBOX_WITH_VIDEOHWACCEL VBoxDispVHWAEnable(pDev); #endif /* Set device palette if needed */ if (pDev->mode.ulBitsPerPel == 8) { rc = VBoxDispSetPalette8BPP(pDev); VBOX_WARNRC_RETV(rc, NULL); } pDev->orgDisp.x = 0; pDev->orgDisp.y = 0; /* Create GDI managed bitmap, which resides in our framebuffer memory */ ULONG iFormat; SIZEL size; switch (pDev->mode.ulBitsPerPel) { case 8: { iFormat = BMF_8BPP; break; } case 16: { iFormat = BMF_16BPP; break; } case 24: { iFormat = BMF_24BPP; break; } case 32: { iFormat = BMF_32BPP; break; } } size.cx = pDev->mode.ulWidth; size.cy = pDev->mode.ulHeight; pDev->surface.hBitmap = EngCreateBitmap(size, pDev->mode.lScanlineStride, iFormat, pDev->mode.lScanlineStride>0 ? BMF_TOPDOWN:0, pDev->memInfo.FrameBufferBase); if (!pDev->surface.hBitmap) { WARN(("EngCreateBitmap failed!")); return NULL; } pDev->surface.psoBitmap = EngLockSurface((HSURF)pDev->surface.hBitmap); /* Create device-managed surface */ pDev->surface.hSurface = EngCreateDeviceSurface((DHSURF)pDev, size, iFormat); if (!pDev->surface.hSurface) { WARN(("EngCreateDeviceSurface failed!")); VBoxDispDrvDisableSurface(dhpdev); return NULL; } FLONG flHooks = HOOK_BITBLT|HOOK_TEXTOUT|HOOK_FILLPATH|HOOK_COPYBITS|HOOK_STROKEPATH|HOOK_LINETO| HOOK_PAINT|HOOK_STRETCHBLT; /* Associate created surface with our device */ if (!EngAssociateSurface(pDev->surface.hSurface, pDev->hDevGDI, flHooks)) { WARN(("EngAssociateSurface failed!")); VBoxDispDrvDisableSurface(dhpdev); return NULL; } pDev->surface.ulFormat = iFormat; pDev->flDrawingHooks = flHooks; LOG(("Created surface %p for physical device %p", pDev->surface.hSurface, pDev)); LOGF_LEAVE(); return pDev->surface.hSurface; }
HBITMAP APIENTRY VBoxDispDrvDeriveSurface(DD_DIRECTDRAW_GLOBAL *pDirectDraw, DD_SURFACE_LOCAL *pSurface) { PVBOXDISPDEV pDev = (PVBOXDISPDEV)pDirectDraw->dhpdev; LOGF_ENTER(); if (pSurface->ddsCaps.dwCaps & DDSCAPS_NONLOCALVIDMEM) { WARN(("Can't derive surface DDSCAPS_NONLOCALVIDMEM")); return NULL; } if (pSurface->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_TEXTUREMANAGE) { WARN(("Can't derive surface DDSCAPS2_TEXTUREMANAGE")); return NULL; } if (pSurface->lpGbl->ddpfSurface.dwRGBBitCount != pDev->mode.ulBitsPerPel) { WARN(("Can't derive surface with different bpp")); return NULL; } Assert(pDev->surface.hSurface); /* Create GDI managed bitmap, which resides in our DDraw heap memory */ HBITMAP hBitmap; SIZEL size; size.cx = pDev->mode.ulWidth; size.cy = pDev->mode.ulHeight; hBitmap = EngCreateBitmap(size, pSurface->lpGbl->lPitch, pDev->surface.ulFormat, pDev->mode.lScanlineStride>0 ? BMF_TOPDOWN:0, (PBYTE)pDev->memInfo.VideoRamBase + pSurface->lpGbl->fpVidMem); if (!hBitmap) { WARN(("EngCreateBitmap failed")); return 0; } if (pSurface->lpGbl->fpVidMem == 0) { /* Screen surface, mark it so it will be recognized by the driver. * so the driver will be called on any operations on the surface * (required for VBVA and VRDP). */ SURFOBJ *pso; if (!EngAssociateSurface((HSURF)hBitmap, pDev->hDevGDI, pDev->flDrawingHooks)) { WARN(("EngAssociateSurface failed")); EngDeleteSurface((HSURF)hBitmap); return NULL; } pso = EngLockSurface((HSURF)hBitmap); if (!pso) { WARN(("EngLockSurface failed")); EngDeleteSurface((HSURF)hBitmap); return NULL; } pso->dhpdev = (DHPDEV)pDev; EngUnlockSurface(pso); } LOGF_LEAVE(); return hBitmap; }
HSURF DrvEnableSurface( DHPDEV dhpdev) { PDEV* ppdev; HSURF hsurfShadow; HSURF hsurfDevice; SIZEL sizl; ppdev = (PDEV*) dhpdev; ///////////////////////////////////////////////////////////////////// // Have GDI create the actual SURFOBJ. // // Our drawing surface is going to be 'device-managed', meaning that // GDI cannot draw on the framebuffer bits directly, and as such we // create the surface via EngCreateSurface. By doing this, we ensure // that GDI will only ever access the bitmaps bits via the Drv calls // that we've HOOKed. sizl.cx = ppdev->cxScreen; sizl.cy = ppdev->cyScreen; hsurfDevice = EngCreateDeviceSurface(NULL, sizl, ppdev->iBitmapFormat); if (hsurfDevice == 0) { DISPDBG((0, "DrvEnableSurface - Failed EngCreateSurface")); goto ReturnFailure; } ppdev->hsurfScreen = hsurfDevice; // Remember it for clean-up ///////////////////////////////////////////////////////////////////// // Now associate the surface and the PDEV. // // We have to associate the surface we just created with our physical // device so that GDI can get information related to the PDEV when // it's drawing to the surface (such as, for example, the length of // styles on the device when simulating styled lines). // if (!EngAssociateSurface(hsurfDevice, ppdev->hdevEng, ppdev->flHooks)) { DISPDBG((0, "DrvEnableSurface - Failed EngAssociateSurface")); goto ReturnFailure; } // Create the 4bpp DIB on which we'll have GDI do all the drawing. // We'll merely occasionally blt portions to the screen to update. sizl.cx = ppdev->cxScreen; sizl.cy = ppdev->cyScreen; hsurfShadow = (HSURF) EngCreateBitmap(sizl, 0, ppdev->iBitmapFormat, 0, NULL); if (hsurfShadow == 0) goto ReturnFailure; if (!EngAssociateSurface(hsurfShadow, ppdev->hdevEng, ppdev->flHooks)) { DISPDBG((0, "DrvEnableSurface - Failed second EngAssociateSurface")); goto ReturnFailure; } ppdev->pso = EngLockSurface(hsurfShadow); if (ppdev->pso == NULL) goto ReturnFailure; ///////////////////////////////////////////////////////////////////// // Now enable all the subcomponents. // // Note that the order in which these 'Enable' functions are called // may be significant in low off-screen memory conditions, because // the off-screen heap manager may fail some of the later // allocations... if (!bEnableHardware(ppdev)) goto ReturnFailure; DISPDBG((5, "Passed DrvEnableSurface")); return(hsurfDevice); ReturnFailure: DrvDisableSurface((DHPDEV) ppdev); DISPDBG((0, "Failed DrvEnableSurface")); return(0); }
HBITMAP DrvCreateDeviceBitmap( DHPDEV dhpdev, SIZEL sizl, ULONG iFormat) { PDEV* ppdev; OH* poh; DSURF* pdsurf; HBITMAP hbmDevice; FLONG flHooks; ppdev = (PDEV*) dhpdev; // If we're in full-screen mode, we hardly have any off-screen memory // in which to allocate a DFB. LATER: We could still allocate an // OH node and put the bitmap on the DIB DFB list for later promotion. if (!ppdev->bEnabled) return(0); // We only support device bitmaps when we're in a fully accelerated // mode: if (ppdev->iBitmapFormat != BMF_8BPP) return(0); // We only support device bitmaps that are the same colour depth // as our display. // // Actually, those are the only kind GDI will ever call us with, // but we may as well check. Note that this implies you'll never // get a crack at 1bpp bitmaps. if (iFormat != ppdev->iBitmapFormat) return(0); poh = pohAllocate(ppdev, sizl.cx, sizl.cy, 0); if (poh != NULL) { pdsurf = EngAllocMem(0, sizeof(DSURF), ALLOC_TAG); if (pdsurf != NULL) { hbmDevice = EngCreateDeviceBitmap((DHSURF) pdsurf, sizl, iFormat); if (hbmDevice != NULL) { flHooks = ppdev->flHooks; #if SYNCHRONIZEACCESS_WORKS { // Setting the SYNCHRONIZEACCESS flag tells GDI that we // want all drawing to the bitmaps to be synchronized (GDI // is multi-threaded and by default does not synchronize // device bitmap drawing -- it would be a Bad Thing for us // to have multiple threads using the accelerator at the // same time): flHooks |= HOOK_SYNCHRONIZEACCESS; } #endif // SYNCHRONIZEACCESS_WORKS if (EngAssociateSurface((HSURF) hbmDevice, ppdev->hdevEng, flHooks)) { pdsurf->dt = DT_SCREEN; pdsurf->poh = poh; pdsurf->sizl = sizl; pdsurf->ppdev = ppdev; poh->pdsurf = pdsurf; return(hbmDevice); } EngDeleteSurface((HSURF) hbmDevice); } EngFreeMem(pdsurf); } pohFree(ppdev, poh); } return(0); }
OH* pohMoveOffscreenDfbToDib( PDEV* ppdev, OH* poh) { DSURF* pdsurf; HBITMAP hbmDib; SURFOBJ* pso; RECTL rclDst; POINTL ptlSrc; DISPDBG((1, "Throwing out %li x %li at (%li, %li)!", poh->cx, poh->cy, poh->x, poh->y)); pdsurf = poh->pdsurf; ASSERTDD((poh->x != 0) || (poh->y != 0), "Can't make the visible screen into a DIB"); ASSERTDD(pdsurf->dt != DT_DIB, "Can't make a DIB into even more of a DIB"); hbmDib = EngCreateBitmap(pdsurf->sizl, 0, ppdev->iBitmapFormat, BMF_TOPDOWN, NULL); if (hbmDib) { if (EngAssociateSurface((HSURF) hbmDib, ppdev->hdevEng, 0)) { pso = EngLockSurface((HSURF) hbmDib); if (pso != NULL) { rclDst.left = 0; rclDst.top = 0; rclDst.right = pdsurf->sizl.cx; rclDst.bottom = pdsurf->sizl.cy; ptlSrc.x = poh->x; ptlSrc.y = poh->y; vGetBits(ppdev, pso, &rclDst, &ptlSrc); pdsurf->dt = DT_DIB; pdsurf->pso = pso; // Don't even bother checking to see if this DIB should // be put back into off-screen memory until the next // heap 'free' occurs: pdsurf->iUniq = ppdev->iHeapUniq; pdsurf->cBlt = 0; // Remove this node from the off-screen DFB list, and free // it. 'pohFree' will never return NULL: return(pohFree(ppdev, poh)); } } // Fail case: EngDeleteSurface((HSURF) hbmDib); } return(NULL); }
HSURF DrvEnableSurface(DHPDEV dhpdev) { PPDEV ppdev; PDEVSURF pdsurf; DHSURF dhsurf; HSURF hsurf; DISPDBG((2, "enabling Surface\n")); ppdev = (PPDEV) dhpdev; // // Initialize the VGA device into the selected mode which will also map // the video frame buffer // if (!bInitVGA(ppdev, TRUE)) { goto error_done; } dhsurf = (DHSURF) EngAllocMem(0, sizeof(DEVSURF), ALLOC_TAG); if (dhsurf == (DHSURF) 0) { goto error_done; } pdsurf = (PDEVSURF) dhsurf; pdsurf->ident = DEVSURF_IDENT; pdsurf->flSurf = 0; pdsurf->iFormat = BMF_PHYSDEVICE; pdsurf->jReserved1 = 0; pdsurf->jReserved2 = 0; pdsurf->ppdev = ppdev; pdsurf->sizlSurf.cx = ppdev->sizlSurf.cx; pdsurf->sizlSurf.cy = ppdev->sizlSurf.cy; pdsurf->lNextPlane = 0; pdsurf->pvScan0 = ppdev->pjScreen; pdsurf->pvBitmapStart = ppdev->pjScreen; pdsurf->pvStart = ppdev->pjScreen; pdsurf->pvConv = &ajConvertBuffer[0]; // Initialize pointer information. // // bInitPointer must be called before bInitSavedBits. // if (!bInitPointer(ppdev)) { DISPDBG((0, "DrvEnablePDEV failed bInitPointer\n")); goto error_clean; } if (!SetUpBanking(pdsurf, ppdev)) { DISPDBG((0, "DrvEnablePDEV failed SetUpBanking\n")); goto error_clean; } if ((hsurf = EngCreateDeviceSurface(dhsurf, ppdev->sizlSurf, BMF_4BPP)) == (HSURF) 0) { DISPDBG((0, "DrvEnablePDEV failed EngCreateDeviceSurface\n")); goto error_clean; } // // vInitSavedBits must be called after bInitPointer. // vInitSavedBits(ppdev); if (EngAssociateSurface(hsurf, ppdev->hdevEng, HOOK_BITBLT | HOOK_TEXTOUT | HOOK_STROKEPATH | HOOK_COPYBITS | HOOK_PAINT | HOOK_FILLPATH )) { ppdev->hsurfEng = hsurf; ppdev->pdsurf = pdsurf; // Set up an empty saved screen block list pdsurf->ssbList = NULL; DISPDBG((2, "enabled surface\n")); return(hsurf); } DISPDBG((0, "DrvEnablePDEV failed EngDeleteSurface\n")); EngDeleteSurface(hsurf); error_clean: // We created the surface, so delete it EngFreeMem(dhsurf); error_done: return((HSURF) 0); }