/* Called before first DDLock/after last DDUnlock to map/unmap surface memory from given process address space * We go easy way and map whole framebuffer and offscreen DirectDraw heap every time. */ DWORD APIENTRY VBoxDispDDMapMemory(PDD_MAPMEMORYDATA lpMapMemory) { PVBOXDISPDEV pDev = (PVBOXDISPDEV) lpMapMemory->lpDD->dhpdev; VIDEO_SHARE_MEMORY smem; int rc; LOGF_ENTER(); lpMapMemory->ddRVal = DDERR_GENERIC; memset(&smem, 0, sizeof(smem)); smem.ProcessHandle = lpMapMemory->hProcess; if (lpMapMemory->bMap) { VIDEO_SHARE_MEMORY_INFORMATION smemInfo; smem.ViewSize = pDev->layout.offDDrawHeap + pDev->layout.cbDDrawHeap; rc = VBoxDispMPShareVideoMemory(pDev->hDriver, &smem, &smemInfo); VBOX_WARNRC_RETV(rc, DDHAL_DRIVER_HANDLED); lpMapMemory->fpProcess = (FLATPTR) smemInfo.VirtualAddress; } else { smem.RequestedVirtualAddress = (PVOID) lpMapMemory->fpProcess; rc = VBoxDispMPUnshareVideoMemory(pDev->hDriver, &smem); VBOX_WARNRC_RETV(rc, DDHAL_DRIVER_HANDLED); } lpMapMemory->ddRVal = DD_OK; LOGF_LEAVE(); return DDHAL_DRIVER_HANDLED; }
/* Returns video modes supported by our device/driver * Note: If we fail here we'd be asked to enter 800x600@4bpp mode later in VBoxDispDrvEnablePDEV. */ ULONG APIENTRY VBoxDispDrvGetModes(HANDLE hDriver, ULONG cjSize, DEVMODEW *pdm) { int rc; VIDEO_MODE_INFORMATION *pModesTable; ULONG cModes; LOGF_ENTER(); rc = VBoxDispMPGetVideoModes(hDriver, &pModesTable, &cModes); VBOX_WARNRC_RETV(rc, 0); if (!pdm) /* return size of buffer required to store all supported modes */ { EngFreeMem(pModesTable); LOGF_LEAVE(); return cModes * sizeof(DEVMODEW); } ULONG mode, cMaxNodes=cjSize/sizeof(DEVMODEW); for (mode=0; mode<cModes && mode<cMaxNodes; ++mode, ++pdm) { memset(pdm, 0, sizeof(DEVMODEW)); memcpy(pdm->dmDeviceName, VBOXDISP_DEVICE_NAME, sizeof(VBOXDISP_DEVICE_NAME)); pdm->dmSpecVersion = DM_SPECVERSION; pdm->dmDriverVersion = DM_SPECVERSION; pdm->dmSize = sizeof(DEVMODEW); pdm->dmDriverExtra = 0; pdm->dmBitsPerPel = pModesTable[mode].NumberOfPlanes*pModesTable[mode].BitsPerPlane; pdm->dmPelsWidth = pModesTable[mode].VisScreenWidth; pdm->dmPelsHeight = pModesTable[mode].VisScreenHeight; pdm->dmDisplayFrequency = pModesTable[mode].Frequency; pdm->dmDisplayFlags = 0; pdm->dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT|DM_DISPLAYFREQUENCY|DM_DISPLAYFLAGS; } EngFreeMem(pModesTable); LOG(("%d mode(s) reported", mode)); LOGF_LEAVE(); return mode * sizeof(DEVMODEW); }
/* 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; }