193
187
VBVACMDHDR cmdHdr;
197
CARD32 indexRecordNext;
201
CARD32 cbHwBufferAvail;
205
192
pVBox = pScrn->driverPrivate;
206
if (pVBox->useVbva == FALSE)
208
pMem = pVBox->pVbvaMemory;
209
/* Just return quietly if VBVA is not currently active. */
210
if ((pMem->fu32ModeFlags & VBVA_F_MODE_ENABLED) == 0)
212
scrnIndex = pScrn->scrnIndex;
214
for (i = 0; i < iRects; i++)
193
if (pVBox->fHaveHGSMI == FALSE || pVBox->vtSwitch)
196
for (i = 0; i < iRects; ++i)
197
for (j = 0; j < pVBox->cScreens; ++j)
199
/* Just continue quietly if VBVA is not currently active. */
200
struct VBVABUFFER *pVBVA = pVBox->aVbvaCtx[j].pVBVA;
202
|| !(pVBVA->hostFlags.u32HostEvents & VBVA_F_MODE_ENABLED))
204
if ( aRects[i].x1 > pVBox->aScreenLocation[j].x
205
+ pVBox->aScreenLocation[j].cx
206
|| aRects[i].y1 > pVBox->aScreenLocation[j].y
207
+ pVBox->aScreenLocation[j].cy
208
|| aRects[i].x2 < pVBox->aScreenLocation[j].x
209
|| aRects[i].y2 < pVBox->aScreenLocation[j].y)
211
cmdHdr.x = (int16_t)aRects[i].x1;
212
cmdHdr.y = (int16_t)aRects[i].y1;
213
cmdHdr.w = (uint16_t)(aRects[i].x2 - aRects[i].x1);
214
cmdHdr.h = (uint16_t)(aRects[i].y2 - aRects[i].y1);
217
TRACE_LOG("display=%u, x=%d, y=%d, w=%d, h=%d\n",
218
j, cmdHdr.x, cmdHdr.y, cmdHdr.w, cmdHdr.h);
221
if (VBoxVBVABufferBeginUpdate(&pVBox->aVbvaCtx[j],
224
VBoxVBVAWrite(&pVBox->aVbvaCtx[j], &pVBox->guestCtx, &cmdHdr,
226
VBoxVBVABufferEndUpdate(&pVBox->aVbvaCtx[j]);
231
/** Callback to fill in the view structures */
233
vboxFillViewInfo(void *pvVBox, struct VBVAINFOVIEW *pViews, uint32_t cViews)
235
VBOXPtr pVBox = (VBOXPtr)pvVBox;
237
for (i = 0; i < cViews; ++i)
216
cmdHdr.x = (int16_t)aRects[i].x1 - pVBox->viewportX;
217
cmdHdr.y = (int16_t)aRects[i].y1 - pVBox->viewportY;
218
cmdHdr.w = (uint16_t)(aRects[i].x2 - aRects[i].x1);
219
cmdHdr.h = (uint16_t)(aRects[i].y2 - aRects[i].y1);
221
/* Get the active record and move the pointer along */
222
indexRecordNext = (pMem->indexRecordFree + 1) % VBVA_MAX_RECORDS;
223
if (indexRecordNext == pMem->indexRecordFirst)
225
/* All slots in the records queue are used. */
226
if (VbglR3VideoAccelFlush() < 0)
227
DISABLE_VBVA_AND_RETURN(pScrn,
228
"Unable to clear the VirtualBox graphics acceleration queue "
229
"- the request to the virtual machine failed. Switching to "
230
"unaccelerated mode.\n");
232
if (indexRecordNext == pMem->indexRecordFirst)
233
DISABLE_VBVA_AND_RETURN(pScrn,
234
"Failed to clear the VirtualBox graphics acceleration queue. "
235
"Switching to unaccelerated mode.\n");
236
pRecord = &pMem->aRecords[pMem->indexRecordFree];
237
/* Mark the record as being updated. */
238
pRecord->cbRecord = VBVA_F_RECORD_PARTIAL;
239
pMem->indexRecordFree = indexRecordNext;
240
/* Compute how many bytes we have in the ring buffer. */
241
off32Free = pMem->off32Free;
242
off32Data = pMem->off32Data;
243
/* Free is writing position. Data is reading position.
244
* Data == Free means buffer is free.
245
* There must be always gap between free and data when data
247
* Guest only changes free, host only changes data.
249
i32Diff = off32Data - off32Free;
250
cbHwBufferAvail = i32Diff > 0 ? i32Diff : VBVA_RING_BUFFER_SIZE + i32Diff;
251
if (cbHwBufferAvail <= VBVA_RING_BUFFER_THRESHOLD)
253
if (VbglR3VideoAccelFlush() < 0)
254
DISABLE_VBVA_AND_RETURN(pScrn,
255
"Unable to clear the VirtualBox graphics acceleration queue "
256
"- the request to the virtual machine failed. Switching to "
257
"unaccelerated mode.\n");
258
/* Calculate the free space again. */
259
off32Free = pMem->off32Free;
260
off32Data = pMem->off32Data;
261
i32Diff = off32Data - off32Free;
262
cbHwBufferAvail = i32Diff > 0? i32Diff:
263
VBVA_RING_BUFFER_SIZE + i32Diff;
264
if (cbHwBufferAvail <= VBVA_RING_BUFFER_THRESHOLD)
265
DISABLE_VBVA_AND_RETURN(pScrn,
266
"No space left in the VirtualBox graphics acceleration command buffer, "
267
"despite clearing the queue. Switching to unaccelerated mode.\n");
269
/* Now copy the data into the buffer */
270
if (off32Free + sizeof(cmdHdr) < VBVA_RING_BUFFER_SIZE)
272
memcpy(&pMem->au8RingBuffer[off32Free], &cmdHdr, sizeof(cmdHdr));
273
pMem->off32Free = pMem->off32Free + sizeof(cmdHdr);
277
CARD32 u32First = VBVA_RING_BUFFER_SIZE - off32Free;
278
/* The following is impressively ugly! */
279
CARD8 *pu8Second = (CARD8 *)&cmdHdr + u32First;
280
CARD32 u32Second = sizeof(cmdHdr) - u32First;
281
memcpy(&pMem->au8RingBuffer[off32Free], &cmdHdr, u32First);
283
memcpy(&pMem->au8RingBuffer[0], pu8Second, u32Second);
284
pMem->off32Free = u32Second;
286
pRecord->cbRecord += sizeof(cmdHdr);
287
/* Mark the record completed. */
288
pRecord->cbRecord &= ~VBVA_F_RECORD_PARTIAL;
239
pViews[i].u32ViewIndex = i;
240
pViews[i].u32ViewOffset = 0;
241
pViews[i].u32ViewSize = pVBox->cbView;
242
pViews[i].u32MaxScreenSize = pVBox->cbFBMax;
293
/* As of X.org server 1.5, we are using the pciaccess library functions to
294
* access PCI. This structure describes our VMM device. */
295
/** Structure describing the VMM device */
296
static const struct pci_id_match vboxVMMDevID =
297
{ VMMDEV_VENDORID, VMMDEV_DEVICEID, PCI_MATCH_ANY, PCI_MATCH_ANY,
302
248
* Initialise VirtualBox's accelerated video extensions.
307
253
vboxInitVbva(int scrnIndex, ScreenPtr pScreen, VBOXPtr pVBox)
310
struct pci_device_iterator *devIter = NULL;
313
pVBox->vmmDevInfo = NULL;
314
devIter = pci_id_match_iterator_create(&vboxVMMDevID);
317
pVBox->vmmDevInfo = pci_device_next(devIter);
318
pci_iterator_destroy(devIter);
320
if (pVBox->vmmDevInfo)
322
if (pci_device_probe(pVBox->vmmDevInfo) != 0)
324
xf86DrvMsg (scrnIndex, X_ERROR,
325
"Failed to probe VMM device (vendor=%04x, devid=%04x)\n",
326
pVBox->vmmDevInfo->vendor_id,
327
pVBox->vmmDevInfo->device_id);
331
if (pci_device_map_range(pVBox->vmmDevInfo,
332
pVBox->vmmDevInfo->regions[1].base_addr,
333
pVBox->vmmDevInfo->regions[1].size,
334
PCI_DEV_MAP_FLAG_WRITABLE,
335
(void **)&pVBox->pVMMDevMemory) != 0)
336
xf86DrvMsg (scrnIndex, X_ERROR,
337
"Failed to map VMM device range\n");
345
/* Locate the device. It should already have been enabled by
346
the kernel driver. */
347
pciTagDev = pciFindFirst((unsigned) VMMDEV_DEVICEID << 16 | VMMDEV_VENDORID,
349
if (pciTagDev == PCI_NOT_FOUND)
351
xf86DrvMsg(scrnIndex, X_ERROR,
352
"Could not find the VirtualBox base device on the PCI bus.\n");
355
/* Read the address and size of the second I/O region. */
356
pciAddrDev = pciReadLong(pciTagDev, PCI_MAP_REG_START + 4);
357
if (pciAddrDev == 0 || pciAddrDev == (CARD32) ~0)
358
RETERROR(scrnIndex, FALSE,
359
"The VirtualBox base device contains an invalid memory address.\n");
360
if (PCI_MAP_IS64BITMEM(pciAddrDev))
361
RETERROR(scrnIndex, FALSE,
362
"The VirtualBox base device has a 64bit mapping address. "
363
"This is currently not supported.\n");
364
/* Map it. We hardcode the size as X does not export the
365
function needed to determine it. */
366
pVBox->pVMMDevMemory = xf86MapPciMem(scrnIndex, 0, pciTagDev, pciAddrDev,
367
sizeof(VMMDevMemory));
369
if (pVBox->pVMMDevMemory == NULL)
371
xf86DrvMsg(scrnIndex, X_ERROR,
372
"Failed to map VirtualBox video extension memory.\n");
375
pVBox->pVbvaMemory = &pVBox->pVMMDevMemory->vbvaMemory;
376
/* Set up the dirty rectangle handler. Since this seems to be a
377
delicate operation, and removing it doubly so, this will
378
remain in place whether it is needed or not, and will simply
379
return if VBVA is not active. I assume that it will be active
255
ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
256
int rc = VINF_SUCCESS;
259
if (!VBoxHGSMIIsSupported())
261
xf86DrvMsg(scrnIndex, X_ERROR, "The graphics device does not seem to support HGSMI. Disableing video acceleration.\n");
265
/* Set up the dirty rectangle handler. It will be added into a function
266
* chain and gets removed when the screen is cleaned up. */
381
267
if (ShadowFBInit2(pScreen, NULL, vboxHandleDirtyRect) != TRUE)
383
269
xf86DrvMsg(scrnIndex, X_ERROR,
277
* Initialise VirtualBox's accelerated video extensions.
279
* @returns TRUE on success, FALSE on failure
282
vboxSetupVRAMVbva(ScrnInfoPtr pScrn, VBOXPtr pVBox)
284
int rc = VINF_SUCCESS;
286
uint32_t offVRAMBaseMapping, offGuestHeapMemory, cbGuestHeapMemory;
287
void *pvGuestHeapMemory;
289
if (!pVBox->fHaveHGSMI)
291
VBoxHGSMIGetBaseMappingInfo(pScrn->videoRam * 1024, &offVRAMBaseMapping,
292
NULL, &offGuestHeapMemory, &cbGuestHeapMemory,
294
pvGuestHeapMemory = ((uint8_t *)pVBox->base) + offVRAMBaseMapping
295
+ offGuestHeapMemory;
296
TRACE_LOG("video RAM: %u KB, guest heap offset: 0x%x, cbGuestHeapMemory: %u\n",
297
pScrn->videoRam, offVRAMBaseMapping + offGuestHeapMemory,
299
rc = VBoxHGSMISetupGuestContext(&pVBox->guestCtx, pvGuestHeapMemory,
301
offVRAMBaseMapping + offGuestHeapMemory);
304
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to set up the guest-to-host communication context, rc=%d\n", rc);
307
pVBox->cbView = pVBox->cbFBMax = offVRAMBaseMapping;
308
pVBox->cScreens = VBoxHGSMIGetMonitorCount(&pVBox->guestCtx);
309
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Requested monitor count: %u\n",
311
for (i = 0; i < pVBox->cScreens; ++i)
313
pVBox->cbFBMax -= VBVA_MIN_BUFFER_SIZE;
314
pVBox->aoffVBVABuffer[i] = pVBox->cbFBMax;
315
TRACE_LOG("VBVA buffer offset for screen %u: 0x%lx\n", i,
316
(unsigned long) pVBox->cbFBMax);
317
VBoxVBVASetupBufferContext(&pVBox->aVbvaCtx[i],
318
pVBox->aoffVBVABuffer[i],
319
VBVA_MIN_BUFFER_SIZE);
321
TRACE_LOG("Maximum framebuffer size: %lu (0x%lx)\n",
322
(unsigned long) pVBox->cbFBMax,
323
(unsigned long) pVBox->cbFBMax);
324
rc = VBoxHGSMISendViewInfo(&pVBox->guestCtx, pVBox->cScreens,
325
vboxFillViewInfo, (void *)pVBox);
328
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to send the view information to the host, rc=%d\n", rc);
391
335
vbox_init(int scrnIndex, VBOXPtr pVBox)
486
if (vbox_host_uses_hwcursor(pScrn)) {
487
pVBox->reqp->fFlags = VBOX_MOUSE_POINTER_VISIBLE;
488
rc = VbglR3SetPointerShapeReq(pVBox->reqp);
489
if (RT_FAILURE(rc)) {
490
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not unhide the virtual mouse pointer.\n");
491
/* Play safe, and disable the hardware cursor until the next mode
492
* switch, since obviously something happened that we didn't
494
pVBox->forceSWCursor = TRUE;
397
if (!vbox_host_uses_hwcursor(pScrn))
399
rc = VBoxHGSMIUpdatePointerShape(&pVBox->guestCtx, VBOX_MOUSE_POINTER_VISIBLE,
400
0, 0, 0, 0, NULL, 0);
401
if (RT_FAILURE(rc)) {
402
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not unhide the virtual mouse pointer.\n");
403
/* Play safe, and disable the hardware cursor until the next mode
404
* switch, since obviously something happened that we didn't
406
pVBox->forceSWCursor = TRUE;
500
411
vbox_vmm_load_cursor_image(ScrnInfoPtr pScrn, VBOXPtr pVBox,
501
unsigned char *image)
412
unsigned char *pvImage)
504
VMMDevReqMousePointer *reqp;
505
reqp = (VMMDevReqMousePointer *)image;
415
struct vboxCursorImage *pImage;
416
pImage = (struct vboxCursorImage *)pvImage;
507
418
#ifdef DEBUG_POINTER
508
vbox_show_shape(reqp->width, reqp->height, 0, image);
419
vbox_show_shape(pImage->cWidth, pImage->cHeight, 0, pvImage);
511
rc = VbglR3SetPointerShapeReq(reqp);
422
rc = VBoxHGSMIUpdatePointerShape(&pVBox->guestCtx, pImage->fFlags,
423
pImage->cHotX, pImage->cHotY, pImage->cWidth, pImage->cHeight,
424
pImage->pPixels, pImage->cbLength);
512
425
if (RT_FAILURE(rc)) {
513
426
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unable to set the virtual mouse pointer image.\n");
514
427
/* Play safe, and disable the hardware cursor until the next mode
763
668
"Error invalid cursor hotspot location %dx%d (max %dx%d)\n",
764
669
bitsp->xhot, bitsp->yhot, w, h);
766
pVBox->pointerSize = w * h * 4 + sizeMask;
767
sizeRequest = pVBox->pointerSize + pVBox->pointerHeaderSize;
768
p = calloc(1, sizeRequest);
671
sizeData = w * h * 4 + sizeMask;
672
p = calloc(1, sizeData);
770
674
RETERROR(scrnIndex, ,
771
675
"Error failed to alloc %lu bytes for cursor\n",
772
(unsigned long)sizeRequest);
774
reqp = (VMMDevReqMousePointer *)p;
775
*reqp = *pVBox->reqp;
778
reqp->xHot = bitsp->xhot;
779
reqp->yHot = bitsp->yhot;
780
reqp->fFlags = VBOX_MOUSE_POINTER_VISIBLE | VBOX_MOUSE_POINTER_SHAPE
781
| VBOX_MOUSE_POINTER_ALPHA;
782
reqp->header.size = sizeRequest;
784
memcpy(p + offsetof(VMMDevReqMousePointer, pointerData) + sizeMask, bitsp->argb, w * h * 4);
676
(unsigned long)sizeData);
678
memcpy(p + sizeMask, bitsp->argb, w * h * 4);
786
680
/* Emulate the AND mask. */
787
pm = p + offsetof(VMMDevReqMousePointer, pointerData);
788
682
pc = bitsp->argb;
790
684
/* Init AND mask to 1 */
1182
1078
* The return type is void as we guarantee we will return some mode.
1184
void vboxGetPreferredMode(ScrnInfoPtr pScrn, uint32_t *pcx,
1080
void vboxGetPreferredMode(ScrnInfoPtr pScrn, uint32_t iScreen, uint32_t *pcx,
1185
1081
uint32_t *pcy, uint32_t *pcBits)
1187
1083
/* Query the host for the preferred resolution and colour depth */
1188
uint32_t cx = 0, cy = 0, iDisplay = 0, cBits = 32;
1084
uint32_t cx = 0, cy = 0, iScreenIn = iScreen, cBits = 32;
1189
1085
VBOXPtr pVBox = pScrn->driverPrivate;
1087
TRACE_LOG("iScreen=%u\n", iScreen);
1089
if ( pVBox->aPreferredSize[iScreen].cx
1090
&& pVBox->aPreferredSize[iScreen].cy)
1092
cx = pVBox->aPreferredSize[iScreen].cx;
1093
cy = pVBox->aPreferredSize[iScreen].cy;
1192
1096
if (pVBox->useDevice)
1194
bool found = vboxGetDisplayChangeRequest(pScrn, &cx, &cy, &cBits, &iDisplay);
1195
if ((cx == 0) || (cy == 0))
1099
found = vboxGetDisplayChangeRequest(pScrn, &cx, &cy, &cBits,
1101
if ((cx == 0) || (cy == 0) || iScreenIn != iScreen)
1198
1104
found = vboxRetrieveVideoMode(pScrn, &cx, &cy, &cBits);