VirtualBox

source: vbox/trunk/src/VBox/Devices/Graphics/DevVGA_VBVA.cpp@ 49420

Last change on this file since 49420 was 49420, checked in by vboxsync, 12 years ago

forward-port and adopt VHWA fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 74.9 KB
Line 
1/* $Id: DevVGA_VBVA.cpp 49420 2013-11-08 15:54:02Z vboxsync $ */
2/** @file
3 * VirtualBox Video Acceleration (VBVA).
4 */
5
6/*
7 * Copyright (C) 2006-2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*******************************************************************************
19* Header Files *
20*******************************************************************************/
21#define LOG_GROUP LOG_GROUP_DEV_VGA
22#include <VBox/vmm/pdmifs.h>
23#include <VBox/vmm/pdmdev.h>
24#include <VBox/vmm/pgm.h>
25#include <VBox/vmm/ssm.h>
26#include <VBox/VMMDev.h>
27#include <VBox/VBoxVideo.h>
28#include <iprt/alloc.h>
29#include <iprt/assert.h>
30#include <iprt/asm.h>
31#include <iprt/string.h>
32#include <iprt/param.h>
33#ifdef VBOX_WITH_VIDEOHWACCEL
34#include <iprt/semaphore.h>
35#endif
36
37#include "DevVGA.h"
38
39/* A very detailed logging. */
40#if 0 // def DEBUG_sunlover
41#define LOGVBVABUFFER(a) LogFlow(a)
42#else
43#define LOGVBVABUFFER(a) do {} while (0)
44#endif
45
46/*******************************************************************************
47* Structures and Typedefs *
48*******************************************************************************/
49typedef struct VBVAPARTIALRECORD
50{
51 uint8_t *pu8;
52 uint32_t cb;
53} VBVAPARTIALRECORD;
54
55typedef struct VBVAVIEW
56{
57 VBVAINFOVIEW view;
58 VBVAINFOSCREEN screen;
59 VBVABUFFER *pVBVA;
60 uint32_t u32VBVAOffset;
61 VBVAPARTIALRECORD partialRecord;
62} VBVAVIEW;
63
64typedef struct VBVAMOUSESHAPEINFO
65{
66 bool fSet;
67 bool fVisible;
68 bool fAlpha;
69 uint32_t u32HotX;
70 uint32_t u32HotY;
71 uint32_t u32Width;
72 uint32_t u32Height;
73 uint32_t cbShape;
74 uint32_t cbAllocated;
75 uint8_t *pu8Shape;
76} VBVAMOUSESHAPEINFO;
77
78/** @todo saved state: save and restore VBVACONTEXT */
79typedef struct VBVACONTEXT
80{
81 uint32_t cViews;
82 VBVAVIEW aViews[64 /* @todo SchemaDefs::MaxGuestMonitors*/];
83 VBVAMOUSESHAPEINFO mouseShapeInfo;
84} VBVACONTEXT;
85
86
87
88/** Copies @a cb bytes from the VBVA ring buffer to the @a pu8Dst.
89 * Used for partial records or for records which cross the ring boundary.
90 */
91static void vbvaFetchBytes (VBVABUFFER *pVBVA, uint8_t *pu8Dst, uint32_t cb)
92{
93 /** @todo replace the 'if' with an assert. The caller must ensure this condition. */
94 if (cb >= pVBVA->cbData)
95 {
96 AssertMsgFailed (("cb = 0x%08X, ring buffer size 0x%08X", cb, pVBVA->cbData));
97 return;
98 }
99
100 const uint32_t u32BytesTillBoundary = pVBVA->cbData - pVBVA->off32Data;
101 const uint8_t *src = &pVBVA->au8Data[pVBVA->off32Data];
102 const int32_t i32Diff = cb - u32BytesTillBoundary;
103
104 if (i32Diff <= 0)
105 {
106 /* Chunk will not cross buffer boundary. */
107 memcpy (pu8Dst, src, cb);
108 }
109 else
110 {
111 /* Chunk crosses buffer boundary. */
112 memcpy (pu8Dst, src, u32BytesTillBoundary);
113 memcpy (pu8Dst + u32BytesTillBoundary, &pVBVA->au8Data[0], i32Diff);
114 }
115
116 /* Advance data offset. */
117 pVBVA->off32Data = (pVBVA->off32Data + cb) % pVBVA->cbData;
118
119 return;
120}
121
122
123static bool vbvaPartialRead (VBVAPARTIALRECORD *pPartialRecord, uint32_t cbRecord, VBVABUFFER *pVBVA)
124{
125 uint8_t *pu8New;
126
127 LOGVBVABUFFER(("vbvaPartialRead: p = %p, cb = %d, cbRecord 0x%08X\n",
128 pPartialRecord->pu8, pPartialRecord->cb, cbRecord));
129
130 if (pPartialRecord->pu8)
131 {
132 Assert (pPartialRecord->cb);
133 pu8New = (uint8_t *)RTMemRealloc (pPartialRecord->pu8, cbRecord);
134 }
135 else
136 {
137 Assert (!pPartialRecord->cb);
138 pu8New = (uint8_t *)RTMemAlloc (cbRecord);
139 }
140
141 if (!pu8New)
142 {
143 /* Memory allocation failed, fail the function. */
144 Log(("vbvaPartialRead: failed to (re)alocate memory for partial record!!! cbRecord 0x%08X\n",
145 cbRecord));
146
147 if (pPartialRecord->pu8)
148 {
149 RTMemFree (pPartialRecord->pu8);
150 }
151
152 pPartialRecord->pu8 = NULL;
153 pPartialRecord->cb = 0;
154
155 return false;
156 }
157
158 /* Fetch data from the ring buffer. */
159 vbvaFetchBytes (pVBVA, pu8New + pPartialRecord->cb, cbRecord - pPartialRecord->cb);
160
161 pPartialRecord->pu8 = pu8New;
162 pPartialRecord->cb = cbRecord;
163
164 return true;
165}
166
167/* For contiguous chunks just return the address in the buffer.
168 * For crossing boundary - allocate a buffer from heap.
169 */
170static bool vbvaFetchCmd (VBVAPARTIALRECORD *pPartialRecord, VBVABUFFER *pVBVA, VBVACMDHDR **ppHdr, uint32_t *pcbCmd)
171{
172 uint32_t indexRecordFirst = pVBVA->indexRecordFirst;
173 uint32_t indexRecordFree = pVBVA->indexRecordFree;
174
175 LOGVBVABUFFER(("first = %d, free = %d\n",
176 indexRecordFirst, indexRecordFree));
177
178 if (indexRecordFirst == indexRecordFree)
179 {
180 /* No records to process. Return without assigning output variables. */
181 return true;
182 }
183
184 uint32_t cbRecordCurrent = ASMAtomicReadU32(&pVBVA->aRecords[indexRecordFirst].cbRecord);
185
186 LOGVBVABUFFER(("cbRecord = 0x%08X, pPartialRecord->cb = 0x%08X\n", cbRecordCurrent, pPartialRecord->cb));
187
188 uint32_t cbRecord = cbRecordCurrent & ~VBVA_F_RECORD_PARTIAL;
189
190 if (pPartialRecord->cb)
191 {
192 /* There is a partial read in process. Continue with it. */
193 Assert (pPartialRecord->pu8);
194
195 LOGVBVABUFFER(("continue partial record cb = %d cbRecord 0x%08X, first = %d, free = %d\n",
196 pPartialRecord->cb, cbRecordCurrent, indexRecordFirst, indexRecordFree));
197
198 if (cbRecord > pPartialRecord->cb)
199 {
200 /* New data has been added to the record. */
201 if (!vbvaPartialRead (pPartialRecord, cbRecord, pVBVA))
202 {
203 return false;
204 }
205 }
206
207 if (!(cbRecordCurrent & VBVA_F_RECORD_PARTIAL))
208 {
209 /* The record is completed by guest. Return it to the caller. */
210 *ppHdr = (VBVACMDHDR *)pPartialRecord->pu8;
211 *pcbCmd = pPartialRecord->cb;
212
213 pPartialRecord->pu8 = NULL;
214 pPartialRecord->cb = 0;
215
216 /* Advance the record index. */
217 pVBVA->indexRecordFirst = (indexRecordFirst + 1) % RT_ELEMENTS(pVBVA->aRecords);
218
219 LOGVBVABUFFER(("partial done ok, data = %d, free = %d\n",
220 pVBVA->off32Data, pVBVA->off32Free));
221 }
222
223 return true;
224 }
225
226 /* A new record need to be processed. */
227 if (cbRecordCurrent & VBVA_F_RECORD_PARTIAL)
228 {
229 /* Current record is being written by guest. '=' is important here,
230 * because the guest will do a FLUSH at this condition.
231 * This partial record is too large for the ring buffer and must
232 * be accumulated in an allocated buffer.
233 */
234 if (cbRecord >= pVBVA->cbData - pVBVA->cbPartialWriteThreshold)
235 {
236 /* Partial read must be started. */
237 if (!vbvaPartialRead (pPartialRecord, cbRecord, pVBVA))
238 {
239 return false;
240 }
241
242 LOGVBVABUFFER(("started partial record cb = 0x%08X cbRecord 0x%08X, first = %d, free = %d\n",
243 pPartialRecord->cb, cbRecordCurrent, indexRecordFirst, indexRecordFree));
244 }
245
246 return true;
247 }
248
249 /* Current record is complete. If it is not empty, process it. */
250 if (cbRecord)
251 {
252 /* The size of largest contiguous chunk in the ring biffer. */
253 uint32_t u32BytesTillBoundary = pVBVA->cbData - pVBVA->off32Data;
254
255 /* The pointer to data in the ring buffer. */
256 uint8_t *src = &pVBVA->au8Data[pVBVA->off32Data];
257
258 /* Fetch or point the data. */
259 if (u32BytesTillBoundary >= cbRecord)
260 {
261 /* The command does not cross buffer boundary. Return address in the buffer. */
262 *ppHdr = (VBVACMDHDR *)src;
263
264 /* Advance data offset. */
265 pVBVA->off32Data = (pVBVA->off32Data + cbRecord) % pVBVA->cbData;
266 }
267 else
268 {
269 /* The command crosses buffer boundary. Rare case, so not optimized. */
270 uint8_t *dst = (uint8_t *)RTMemAlloc (cbRecord);
271
272 if (!dst)
273 {
274 LogFlowFunc (("could not allocate %d bytes from heap!!!\n", cbRecord));
275 pVBVA->off32Data = (pVBVA->off32Data + cbRecord) % pVBVA->cbData;
276 return false;
277 }
278
279 vbvaFetchBytes (pVBVA, dst, cbRecord);
280
281 *ppHdr = (VBVACMDHDR *)dst;
282
283 LOGVBVABUFFER(("Allocated from heap %p\n", dst));
284 }
285 }
286
287 *pcbCmd = cbRecord;
288
289 /* Advance the record index. */
290 pVBVA->indexRecordFirst = (indexRecordFirst + 1) % RT_ELEMENTS(pVBVA->aRecords);
291
292 LOGVBVABUFFER(("done ok, data = %d, free = %d\n",
293 pVBVA->off32Data, pVBVA->off32Free));
294
295 return true;
296}
297
298static void vbvaReleaseCmd (VBVAPARTIALRECORD *pPartialRecord, VBVABUFFER *pVBVA, VBVACMDHDR *pHdr, uint32_t cbCmd)
299{
300 uint8_t *au8RingBuffer = &pVBVA->au8Data[0];
301
302 if ( (uint8_t *)pHdr >= au8RingBuffer
303 && (uint8_t *)pHdr < &au8RingBuffer[pVBVA->cbData])
304 {
305 /* The pointer is inside ring buffer. Must be continuous chunk. */
306 Assert (pVBVA->cbData - ((uint8_t *)pHdr - au8RingBuffer) >= cbCmd);
307
308 /* Do nothing. */
309
310 Assert (!pPartialRecord->pu8 && pPartialRecord->cb == 0);
311 }
312 else
313 {
314 /* The pointer is outside. It is then an allocated copy. */
315 LOGVBVABUFFER(("Free heap %p\n", pHdr));
316
317 if ((uint8_t *)pHdr == pPartialRecord->pu8)
318 {
319 pPartialRecord->pu8 = NULL;
320 pPartialRecord->cb = 0;
321 }
322 else
323 {
324 Assert (!pPartialRecord->pu8 && pPartialRecord->cb == 0);
325 }
326
327 RTMemFree (pHdr);
328 }
329
330 return;
331}
332
333static int vbvaFlushProcess (unsigned uScreenId, PVGASTATE pVGAState, VBVAPARTIALRECORD *pPartialRecord, VBVABUFFER *pVBVA)
334{
335 LOGVBVABUFFER(("uScreenId %d, indexRecordFirst = %d, indexRecordFree = %d, off32Data = %d, off32Free = %d\n",
336 uScreenId, pVBVA->indexRecordFirst, pVBVA->indexRecordFree, pVBVA->off32Data, pVBVA->off32Free));
337 struct {
338 /* The rectangle that includes all dirty rectangles. */
339 int32_t xLeft;
340 int32_t xRight;
341 int32_t yTop;
342 int32_t yBottom;
343 } dirtyRect;
344 RT_ZERO(dirtyRect);
345
346 bool fUpdate = false; /* Whether there were any updates. */
347 bool fDirtyEmpty = true;
348
349 for (;;)
350 {
351 VBVACMDHDR *phdr = NULL;
352 uint32_t cbCmd = ~0;
353
354 /* Fetch the command data. */
355 if (!vbvaFetchCmd (pPartialRecord, pVBVA, &phdr, &cbCmd))
356 {
357 LogFunc(("unable to fetch command. off32Data = %d, off32Free = %d!!!\n",
358 pVBVA->off32Data, pVBVA->off32Free));
359
360 /* @todo old code disabled VBVA processing here. */
361 return VERR_NOT_SUPPORTED;
362 }
363
364 if (cbCmd == uint32_t(~0))
365 {
366 /* No more commands yet in the queue. */
367 break;
368 }
369
370 if (cbCmd != 0)
371 {
372 if (!fUpdate)
373 {
374 pVGAState->pDrv->pfnVBVAUpdateBegin (pVGAState->pDrv, uScreenId);
375 fUpdate = true;
376 }
377
378 /* Updates the rectangle and sends the command to the VRDP server. */
379 pVGAState->pDrv->pfnVBVAUpdateProcess (pVGAState->pDrv, uScreenId, phdr, cbCmd);
380
381 int32_t xRight = phdr->x + phdr->w;
382 int32_t yBottom = phdr->y + phdr->h;
383
384 /* These are global coords, relative to the primary screen. */
385
386 LOGVBVABUFFER(("cbCmd = %d, x=%d, y=%d, w=%d, h=%d\n",
387 cbCmd, phdr->x, phdr->y, phdr->w, phdr->h));
388 LogRel3(("%s: update command cbCmd = %d, x=%d, y=%d, w=%d, h=%d\n",
389 __PRETTY_FUNCTION__, cbCmd, phdr->x, phdr->y, phdr->w,
390 phdr->h));
391
392 /* Collect all rects into one. */
393 if (fDirtyEmpty)
394 {
395 /* This is the first rectangle to be added. */
396 dirtyRect.xLeft = phdr->x;
397 dirtyRect.yTop = phdr->y;
398 dirtyRect.xRight = xRight;
399 dirtyRect.yBottom = yBottom;
400 fDirtyEmpty = false;
401 }
402 else
403 {
404 /* Adjust region coordinates. */
405 if (dirtyRect.xLeft > phdr->x)
406 {
407 dirtyRect.xLeft = phdr->x;
408 }
409
410 if (dirtyRect.yTop > phdr->y)
411 {
412 dirtyRect.yTop = phdr->y;
413 }
414
415 if (dirtyRect.xRight < xRight)
416 {
417 dirtyRect.xRight = xRight;
418 }
419
420 if (dirtyRect.yBottom < yBottom)
421 {
422 dirtyRect.yBottom = yBottom;
423 }
424 }
425 }
426
427 vbvaReleaseCmd (pPartialRecord, pVBVA, phdr, cbCmd);
428 }
429
430 if (fUpdate)
431 {
432 if (dirtyRect.xRight - dirtyRect.xLeft)
433 {
434 LogRel3(("%s: sending update screen=%d, x=%d, y=%d, w=%d, h=%d\n",
435 __PRETTY_FUNCTION__, uScreenId, dirtyRect.xLeft,
436 dirtyRect.yTop, dirtyRect.xRight - dirtyRect.xLeft,
437 dirtyRect.yBottom - dirtyRect.yTop));
438 pVGAState->pDrv->pfnVBVAUpdateEnd (pVGAState->pDrv, uScreenId, dirtyRect.xLeft, dirtyRect.yTop,
439 dirtyRect.xRight - dirtyRect.xLeft, dirtyRect.yBottom - dirtyRect.yTop);
440 }
441 else
442 {
443 pVGAState->pDrv->pfnVBVAUpdateEnd (pVGAState->pDrv, uScreenId, 0, 0, 0, 0);
444 }
445 }
446
447 return VINF_SUCCESS;
448}
449
450static int vbvaFlush (PVGASTATE pVGAState, VBVACONTEXT *pCtx)
451{
452 unsigned uScreenId;
453
454 for (uScreenId = 0; uScreenId < pCtx->cViews; uScreenId++)
455 {
456 VBVAPARTIALRECORD *pPartialRecord = &pCtx->aViews[uScreenId].partialRecord;
457 VBVABUFFER *pVBVA = pCtx->aViews[uScreenId].pVBVA;
458
459 if (pVBVA)
460 {
461 vbvaFlushProcess (uScreenId, pVGAState, pPartialRecord, pVBVA);
462 }
463 }
464
465 /* @todo rc */
466 return VINF_SUCCESS;
467}
468
469static int vbvaResize (PVGASTATE pVGAState, VBVAVIEW *pView, const VBVAINFOSCREEN *pNewScreen)
470{
471 /* Verify pNewScreen. */
472 /* @todo */
473
474 /* Apply these changes. */
475 pView->screen = *pNewScreen;
476
477 uint8_t *pu8VRAM = pVGAState->vram_ptrR3 + pView->view.u32ViewOffset;
478
479 int rc = pVGAState->pDrv->pfnVBVAResize (pVGAState->pDrv, &pView->view, &pView->screen, pu8VRAM);
480
481 /* @todo process VINF_VGA_RESIZE_IN_PROGRESS? */
482
483 return rc;
484}
485
486static int vbvaEnable (unsigned uScreenId, PVGASTATE pVGAState, VBVACONTEXT *pCtx, VBVABUFFER *pVBVA, uint32_t u32Offset, bool fRestored)
487{
488 /* @todo old code did a UpdateDisplayAll at this place. */
489
490 int rc;
491
492 if (pVGAState->pDrv->pfnVBVAEnable)
493 {
494 pVBVA->hostFlags.u32HostEvents = 0;
495 pVBVA->hostFlags.u32SupportedOrders = 0;
496
497 rc = pVGAState->pDrv->pfnVBVAEnable (pVGAState->pDrv, uScreenId, &pVBVA->hostFlags);
498 }
499 else
500 {
501 rc = VERR_NOT_SUPPORTED;
502 }
503
504 if (RT_SUCCESS (rc))
505 {
506 /* pVBVA->hostFlags has been set up by pfnVBVAEnable. */
507 LogFlowFunc(("u32HostEvents 0x%08X, u32SupportedOrders 0x%08X\n",
508 pVBVA->hostFlags.u32HostEvents, pVBVA->hostFlags.u32SupportedOrders));
509
510 if (!fRestored)
511 {
512 /* @todo Actually this function must not touch the partialRecord structure at all,
513 * because initially it is a zero and when VBVA is disabled this should be set to zero.
514 * But I'm not sure that no code depends on zeroing partialRecord here.
515 * So for now (a quick fix for 4.1) just do not do this if the VM was restored,
516 * when partialRecord might be loaded already from the saved state.
517 */
518 pCtx->aViews[uScreenId].partialRecord.pu8 = NULL;
519 pCtx->aViews[uScreenId].partialRecord.cb = 0;
520 }
521
522 pCtx->aViews[uScreenId].pVBVA = pVBVA;
523 pCtx->aViews[uScreenId].u32VBVAOffset = u32Offset;
524 }
525
526 return rc;
527}
528
529static int vbvaDisable (unsigned uScreenId, PVGASTATE pVGAState, VBVACONTEXT *pCtx)
530{
531 /* Process any pending orders and empty the VBVA ring buffer. */
532 vbvaFlush (pVGAState, pCtx);
533
534 VBVAVIEW *pView = &pCtx->aViews[uScreenId];
535
536 if (pView->pVBVA)
537 {
538 pView->pVBVA->hostFlags.u32HostEvents = 0;
539 pView->pVBVA->hostFlags.u32SupportedOrders = 0;
540
541 pView->partialRecord.pu8 = NULL;
542 pView->partialRecord.cb = 0;
543
544 pView->pVBVA = NULL;
545 pView->u32VBVAOffset = HGSMIOFFSET_VOID;
546 }
547
548 pVGAState->pDrv->pfnVBVADisable (pVGAState->pDrv, uScreenId);
549 return VINF_SUCCESS;
550}
551
552bool VBVAIsEnabled(PVGASTATE pVGAState)
553{
554 PHGSMIINSTANCE pHGSMI = pVGAState->pHGSMI;
555 if (pHGSMI)
556 {
557 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pHGSMI);
558 if (pCtx)
559 {
560 if (pCtx->cViews)
561 {
562 VBVAVIEW * pView = &pCtx->aViews[0];
563 if (pView->pVBVA)
564 return true;
565 }
566 }
567 }
568 return false;
569}
570
571#ifdef DEBUG_sunlover
572void dumpMouseShapeInfo(const VBVAMOUSESHAPEINFO *pMouseShapeInfo)
573{
574 LogFlow(("fSet = %d, fVisible %d, fAlpha %d, @%d,%d %dx%d (%p, %d/%d)\n",
575 pMouseShapeInfo->fSet,
576 pMouseShapeInfo->fVisible,
577 pMouseShapeInfo->fAlpha,
578 pMouseShapeInfo->u32HotX,
579 pMouseShapeInfo->u32HotY,
580 pMouseShapeInfo->u32Width,
581 pMouseShapeInfo->u32Height,
582 pMouseShapeInfo->pu8Shape,
583 pMouseShapeInfo->cbShape,
584 pMouseShapeInfo->cbAllocated
585 ));
586}
587#endif
588
589static int vbvaUpdateMousePointerShape(PVGASTATE pVGAState, VBVAMOUSESHAPEINFO *pMouseShapeInfo, bool fShape, const uint8_t *pu8Shape)
590{
591 int rc;
592 LogFlowFunc(("pVGAState %p, pMouseShapeInfo %p, fShape %d, pu8Shape %p\n",
593 pVGAState, pMouseShapeInfo, fShape, pu8Shape));
594#ifdef DEBUG_sunlover
595 dumpMouseShapeInfo(pMouseShapeInfo);
596#endif
597
598 if (fShape && pu8Shape != NULL)
599 {
600 rc = pVGAState->pDrv->pfnVBVAMousePointerShape (pVGAState->pDrv,
601 pMouseShapeInfo->fVisible,
602 pMouseShapeInfo->fAlpha,
603 pMouseShapeInfo->u32HotX,
604 pMouseShapeInfo->u32HotY,
605 pMouseShapeInfo->u32Width,
606 pMouseShapeInfo->u32Height,
607 pu8Shape);
608 }
609 else
610 {
611 rc = pVGAState->pDrv->pfnVBVAMousePointerShape (pVGAState->pDrv,
612 pMouseShapeInfo->fVisible,
613 false,
614 0, 0,
615 0, 0,
616 NULL);
617 }
618
619 return rc;
620}
621
622static int vbvaMousePointerShape (PVGASTATE pVGAState, VBVACONTEXT *pCtx, const VBVAMOUSEPOINTERSHAPE *pShape, HGSMISIZE cbShape)
623{
624 bool fVisible = (pShape->fu32Flags & VBOX_MOUSE_POINTER_VISIBLE) != 0;
625 bool fAlpha = (pShape->fu32Flags & VBOX_MOUSE_POINTER_ALPHA) != 0;
626 bool fShape = (pShape->fu32Flags & VBOX_MOUSE_POINTER_SHAPE) != 0;
627
628 HGSMISIZE cbPointerData = 0;
629
630 if (fShape)
631 {
632 cbPointerData = ((((pShape->u32Width + 7) / 8) * pShape->u32Height + 3) & ~3)
633 + pShape->u32Width * 4 * pShape->u32Height;
634 }
635
636 if (cbPointerData > cbShape - RT_OFFSETOF(VBVAMOUSEPOINTERSHAPE, au8Data))
637 {
638 Log(("vbvaMousePointerShape: calculated pointer data size is too big (%d bytes, limit %d)\n",
639 cbPointerData, cbShape - RT_OFFSETOF(VBVAMOUSEPOINTERSHAPE, au8Data)));
640 return VERR_INVALID_PARAMETER;
641 }
642
643 /* Save mouse info it will be used to restore mouse pointer after restoring saved state. */
644 pCtx->mouseShapeInfo.fSet = true;
645 pCtx->mouseShapeInfo.fVisible = fVisible;
646 pCtx->mouseShapeInfo.fAlpha = fAlpha;
647 if (fShape)
648 {
649 /* Data related to shape. */
650 pCtx->mouseShapeInfo.u32HotX = pShape->u32HotX;
651 pCtx->mouseShapeInfo.u32HotY = pShape->u32HotY;
652 pCtx->mouseShapeInfo.u32Width = pShape->u32Width;
653 pCtx->mouseShapeInfo.u32Height = pShape->u32Height;
654
655 /* Reallocate memory buffer if necessary. */
656 if (cbPointerData > pCtx->mouseShapeInfo.cbAllocated)
657 {
658 RTMemFree (pCtx->mouseShapeInfo.pu8Shape);
659 pCtx->mouseShapeInfo.pu8Shape = NULL;
660 pCtx->mouseShapeInfo.cbShape = 0;
661
662 uint8_t *pu8Shape = (uint8_t *)RTMemAlloc (cbPointerData);
663 if (pu8Shape)
664 {
665 pCtx->mouseShapeInfo.pu8Shape = pu8Shape;
666 pCtx->mouseShapeInfo.cbAllocated = cbPointerData;
667 }
668 }
669
670 /* Copy shape bitmaps. */
671 if (pCtx->mouseShapeInfo.pu8Shape)
672 {
673 memcpy (pCtx->mouseShapeInfo.pu8Shape, &pShape->au8Data[0], cbPointerData);
674 pCtx->mouseShapeInfo.cbShape = cbPointerData;
675 }
676 }
677
678 if (pVGAState->pDrv->pfnVBVAMousePointerShape == NULL)
679 {
680 return VERR_NOT_SUPPORTED;
681 }
682
683 int rc = vbvaUpdateMousePointerShape(pVGAState, &pCtx->mouseShapeInfo, fShape, &pShape->au8Data[0]);
684
685 return rc;
686}
687
688static unsigned vbvaViewFromOffset (PHGSMIINSTANCE pIns, VBVACONTEXT *pCtx, const void *pvBuffer)
689{
690 /* Check which view contains the buffer. */
691 HGSMIOFFSET offBuffer = HGSMIPointerToOffsetHost (pIns, pvBuffer);
692
693 if (offBuffer != HGSMIOFFSET_VOID)
694 {
695 unsigned uScreenId;
696
697 for (uScreenId = 0; uScreenId < pCtx->cViews; uScreenId++)
698 {
699 VBVAINFOVIEW *pView = &pCtx->aViews[uScreenId].view;
700
701 if ( pView->u32ViewSize > 0
702 && pView->u32ViewOffset <= offBuffer
703 && offBuffer <= pView->u32ViewOffset + pView->u32ViewSize - 1)
704 {
705 return pView->u32ViewIndex;
706 }
707 }
708 }
709
710 return ~0U;
711}
712
713#ifdef DEBUG_sunlover
714static void dumpctx(const VBVACONTEXT *pCtx)
715{
716 Log(("VBVACONTEXT dump: cViews %d\n", pCtx->cViews));
717
718 uint32_t iView;
719 for (iView = 0; iView < pCtx->cViews; iView++)
720 {
721 const VBVAVIEW *pView = &pCtx->aViews[iView];
722
723 Log((" view %d o 0x%x s 0x%x m 0x%x\n",
724 pView->view.u32ViewIndex,
725 pView->view.u32ViewOffset,
726 pView->view.u32ViewSize,
727 pView->view.u32MaxScreenSize));
728
729 Log((" screen %d @%d,%d s 0x%x l 0x%x %dx%d bpp %d f 0x%x\n",
730 pView->screen.u32ViewIndex,
731 pView->screen.i32OriginX,
732 pView->screen.i32OriginY,
733 pView->screen.u32StartOffset,
734 pView->screen.u32LineSize,
735 pView->screen.u32Width,
736 pView->screen.u32Height,
737 pView->screen.u16BitsPerPixel,
738 pView->screen.u16Flags));
739
740 Log((" VBVA o 0x%x p %p\n",
741 pView->u32VBVAOffset,
742 pView->pVBVA));
743
744 Log((" PR cb 0x%x p %p\n",
745 pView->partialRecord.cb,
746 pView->partialRecord.pu8));
747 }
748
749 dumpMouseShapeInfo(&pCtx->mouseShapeInfo);
750}
751#endif /* DEBUG_sunlover */
752
753#define VBOXVBVASAVEDSTATE_VHWAAVAILABLE_MAGIC 0x12345678
754#define VBOXVBVASAVEDSTATE_VHWAUNAVAILABLE_MAGIC 0x9abcdef0
755
756#ifdef VBOX_WITH_VIDEOHWACCEL
757static void vbvaVHWAHHCommandReinit(VBOXVHWACMD* pHdr, VBOXVHWACMD_TYPE enmCmd, int32_t iDisplay)
758{
759 memset(pHdr, 0, VBOXVHWACMD_HEADSIZE());
760 pHdr->cRefs = 1;
761 pHdr->iDisplay = iDisplay;
762 pHdr->rc = VERR_NOT_IMPLEMENTED;
763 pHdr->enmCmd = enmCmd;
764 pHdr->Flags = VBOXVHWACMD_FLAG_HH_CMD;
765}
766
767static VBOXVHWACMD* vbvaVHWAHHCommandCreate (PVGASTATE pVGAState, VBOXVHWACMD_TYPE enmCmd, int32_t iDisplay, VBOXVHWACMD_LENGTH cbCmd)
768{
769 VBOXVHWACMD* pHdr = (VBOXVHWACMD*)RTMemAllocZ(cbCmd + VBOXVHWACMD_HEADSIZE());
770 Assert(pHdr);
771 if (pHdr)
772 vbvaVHWAHHCommandReinit(pHdr, enmCmd, iDisplay);
773
774 return pHdr;
775}
776
777DECLINLINE(void) vbvaVHWAHHCommandRelease (VBOXVHWACMD* pCmd)
778{
779 uint32_t cRefs = ASMAtomicDecU32(&pCmd->cRefs);
780 if(!cRefs)
781 {
782 RTMemFree(pCmd);
783 }
784}
785
786DECLINLINE(void) vbvaVHWAHHCommandRetain (VBOXVHWACMD* pCmd)
787{
788 ASMAtomicIncU32(&pCmd->cRefs);
789}
790
791static void vbvaVHWACommandComplete(PVGASTATE pVGAState, PVBOXVHWACMD pCommand, bool fAsyncCommand)
792{
793 if (fAsyncCommand)
794 {
795 Assert(pCommand->Flags & VBOXVHWACMD_FLAG_HG_ASYNCH);
796 vbvaVHWACommandCompleteAsynch(&pVGAState->IVBVACallbacks, pCommand);
797 }
798 else
799 {
800 Log(("VGA Command <<< Sync rc %d %#p, %d\n", pCommand->rc, pCommand, pCommand->enmCmd));
801 pCommand->Flags &= (~VBOXVHWACMD_FLAG_HG_ASYNCH);
802 }
803
804}
805
806static void vbvaVHWACommandCompleteAllPending(PVGASTATE pVGAState, int rc)
807{
808 if (!pVGAState->pendingVhwaCommands.cPending)
809 return;
810
811 VBOX_VHWA_PENDINGCMD *pIter, *pNext;
812 RTListForEachSafe(&pVGAState->pendingVhwaCommands.PendingList, pIter, pNext, VBOX_VHWA_PENDINGCMD, Node)
813 {
814 pIter->pCommand->rc = rc;
815 vbvaVHWACommandComplete(pVGAState, pIter->pCommand, true);
816
817 /* the command is submitted/processed, remove from the pend list */
818 RTListNodeRemove(&pIter->Node);
819 --pVGAState->pendingVhwaCommands.cPending;
820 RTMemFree(pIter);
821 }
822}
823
824static void vbvaVHWACommandCClearAllPending(PVGASTATE pVGAState)
825{
826 if (!pVGAState->pendingVhwaCommands.cPending)
827 return;
828
829 VBOX_VHWA_PENDINGCMD *pIter, *pNext;
830 RTListForEachSafe(&pVGAState->pendingVhwaCommands.PendingList, pIter, pNext, VBOX_VHWA_PENDINGCMD, Node)
831 {
832 RTListNodeRemove(&pIter->Node);
833 --pVGAState->pendingVhwaCommands.cPending;
834 RTMemFree(pIter);
835 }
836}
837
838static void vbvaVHWACommandPend(PVGASTATE pVGAState, PVBOXVHWACMD pCommand)
839{
840 int rc = VERR_BUFFER_OVERFLOW;
841
842 if (pVGAState->pendingVhwaCommands.cPending < VBOX_VHWA_MAX_PENDING_COMMANDS)
843 {
844 VBOX_VHWA_PENDINGCMD *pPend = (VBOX_VHWA_PENDINGCMD*)RTMemAlloc(sizeof (*pPend));
845 if (pPend)
846 {
847 pCommand->Flags |= VBOXVHWACMD_FLAG_HG_ASYNCH;
848 pPend->pCommand = pCommand;
849 RTListAppend(&pVGAState->pendingVhwaCommands.PendingList, &pPend->Node);
850 ++pVGAState->pendingVhwaCommands.cPending;
851 return;
852 }
853 else
854 rc = VERR_NO_MEMORY;
855 }
856 else
857 {
858 LogRel(("Pending command count has reached its threshold, completing them all.."));
859 }
860
861 vbvaVHWACommandCompleteAllPending(pVGAState, rc);
862
863 pCommand->rc = rc;
864
865 vbvaVHWACommandComplete(pVGAState, pCommand, false);
866}
867
868static bool vbvaVHWACommandCanPend(PVBOXVHWACMD pCommand)
869{
870 switch (pCommand->enmCmd)
871 {
872 case VBOXVHWACMD_TYPE_HH_CONSTRUCT:
873 case VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEBEGIN:
874 case VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEEND:
875 case VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEPERFORM:
876 case VBOXVHWACMD_TYPE_HH_SAVESTATE_LOADPERFORM:
877 return false;
878 default:
879 return true;
880 }
881}
882
883static int vbvaVHWACommandSavePending(PVGASTATE pVGAState, PSSMHANDLE pSSM)
884{
885 int rc = SSMR3PutU32(pSSM, pVGAState->pendingVhwaCommands.cPending);
886 AssertRCReturn(rc, rc);
887 VBOX_VHWA_PENDINGCMD *pIter;
888 RTListForEach(&pVGAState->pendingVhwaCommands.PendingList, pIter, VBOX_VHWA_PENDINGCMD, Node)
889 {
890 rc = SSMR3PutU32(pSSM, (uint32_t)(((uint8_t*)pIter->pCommand) - ((uint8_t*)pVGAState->vram_ptrR3)));
891 AssertRCReturn(rc, rc);
892 }
893 return rc;
894}
895
896static int vbvaVHWACommandLoadPending(PVGASTATE pVGAState, PSSMHANDLE pSSM, uint32_t u32Version)
897{
898 if (u32Version < VGA_SAVEDSTATE_VERSION_WITH_PENDVHWA)
899 return VINF_SUCCESS;
900
901 int rc;
902 uint32_t u32;
903 rc = SSMR3GetU32(pSSM, &u32);
904 AssertRCReturn(rc, rc);
905 for (uint32_t i = 0; i < u32; ++i)
906 {
907 uint32_t off32;
908 rc = SSMR3GetU32(pSSM, &off32);
909 AssertRCReturn(rc, rc);
910 PVBOXVHWACMD pCommand = (PVBOXVHWACMD)(((uint8_t*)pVGAState->vram_ptrR3) + off32);
911 vbvaVHWACommandPend(pVGAState, pCommand);
912 }
913 return rc;
914}
915
916
917static bool vbvaVHWACommandSubmit(PVGASTATE pVGAState, PVBOXVHWACMD pCommand, bool fAsyncCommand)
918{
919 unsigned id = (unsigned)pCommand->iDisplay;
920 int rc = VINF_SUCCESS;
921 bool fPend = false;
922
923 if (pVGAState->pDrv->pfnVHWACommandProcess)
924 {
925 Log(("VGA Command >>> %#p, %d\n", pCommand, pCommand->enmCmd));
926 int rc = pVGAState->pDrv->pfnVHWACommandProcess(pVGAState->pDrv, pCommand);
927 if (rc == VINF_CALLBACK_RETURN)
928 {
929 Log(("VGA Command --- Going Async %#p, %d\n", pCommand, pCommand->enmCmd));
930 return true; /* command will be completed asynchronously, return right away */
931 }
932 else if (rc == VERR_INVALID_STATE)
933 {
934 Log(("VGA Command --- Trying Pend %#p, %d\n", pCommand, pCommand->enmCmd));
935 fPend = vbvaVHWACommandCanPend(pCommand);
936 if (!fPend)
937 {
938 Log(("VGA Command --- Can NOT Pend %#p, %d\n", pCommand, pCommand->enmCmd));
939 pCommand->rc = rc;
940 }
941 else
942 Log(("VGA Command --- Can Pend %#p, %d\n", pCommand, pCommand->enmCmd));
943 }
944 else
945 {
946 Log(("VGA Command --- Going Complete Sync rc %d %#p, %d\n", rc, pCommand, pCommand->enmCmd));
947 pCommand->rc = rc;
948 }
949
950 /* the command was completed, take a special care about it (seee below) */
951 }
952 else
953 {
954 AssertFailed();
955 pCommand->rc = VERR_INVALID_STATE;
956 }
957
958 if (fPend)
959 return false;
960
961 vbvaVHWACommandComplete(pVGAState, pCommand, fAsyncCommand);
962
963 return true;
964}
965
966static bool vbvaVHWACheckPendingCommands(PVGASTATE pVGAState)
967{
968 if (!pVGAState->pendingVhwaCommands.cPending)
969 return true;
970
971 VBOX_VHWA_PENDINGCMD *pIter, *pNext;
972 RTListForEachSafe(&pVGAState->pendingVhwaCommands.PendingList, pIter, pNext, VBOX_VHWA_PENDINGCMD, Node)
973 {
974 if (!vbvaVHWACommandSubmit(pVGAState, pIter->pCommand, true))
975 return false; /* the command should be pended still */
976
977 /* the command is submitted/processed, remove from the pend list */
978 RTListNodeRemove(&pIter->Node);
979 --pVGAState->pendingVhwaCommands.cPending;
980 RTMemFree(pIter);
981 }
982
983 return true;
984}
985
986void vbvaTimerCb(PVGASTATE pVGAState)
987{
988 vbvaVHWACheckPendingCommands(pVGAState);
989}
990static void vbvaVHWAHandleCommand(PVGASTATE pVGAState, PVBOXVHWACMD pCmd)
991{
992 if (vbvaVHWACheckPendingCommands(pVGAState))
993 {
994 if (vbvaVHWACommandSubmit(pVGAState, pCmd, false))
995 return;
996 }
997
998 vbvaVHWACommandPend(pVGAState, pCmd);
999}
1000
1001static DECLCALLBACK(void) vbvaVHWAHHCommandSetEventCallback(void * pContext)
1002{
1003 RTSemEventSignal((RTSEMEVENT)pContext);
1004}
1005
1006static int vbvaVHWAHHCommandPost(PVGASTATE pVGAState, VBOXVHWACMD* pCmd)
1007{
1008 RTSEMEVENT hComplEvent;
1009 int rc = RTSemEventCreate(&hComplEvent);
1010 AssertRC(rc);
1011 if(RT_SUCCESS(rc))
1012 {
1013 /* ensure the cmd is not deleted until we process it */
1014 vbvaVHWAHHCommandRetain (pCmd);
1015 VBOXVHWA_HH_CALLBACK_SET(pCmd, vbvaVHWAHHCommandSetEventCallback, (void*)hComplEvent);
1016 vbvaVHWAHandleCommand(pVGAState, pCmd);
1017 if((ASMAtomicReadU32((volatile uint32_t *)&pCmd->Flags) & VBOXVHWACMD_FLAG_HG_ASYNCH) != 0)
1018 {
1019 rc = RTSemEventWaitNoResume(hComplEvent, RT_INDEFINITE_WAIT);
1020 }
1021 else
1022 {
1023 /* the command is completed */
1024 }
1025
1026 AssertRC(rc);
1027 if(RT_SUCCESS(rc))
1028 {
1029 RTSemEventDestroy(hComplEvent);
1030 }
1031 vbvaVHWAHHCommandRelease(pCmd);
1032 }
1033 return rc;
1034}
1035
1036int vbvaVHWAConstruct (PVGASTATE pVGAState)
1037{
1038 pVGAState->pendingVhwaCommands.cPending = 0;
1039 RTListInit(&pVGAState->pendingVhwaCommands.PendingList);
1040 VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(pVGAState, VBOXVHWACMD_TYPE_HH_CONSTRUCT, 0, sizeof(VBOXVHWACMD_HH_CONSTRUCT));
1041 Assert(pCmd);
1042 if(pCmd)
1043 {
1044 uint32_t iDisplay = 0;
1045 int rc = VINF_SUCCESS;
1046 VBOXVHWACMD_HH_CONSTRUCT * pBody = VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_HH_CONSTRUCT);
1047
1048 do
1049 {
1050 memset(pBody, 0, sizeof(VBOXVHWACMD_HH_CONSTRUCT));
1051
1052 PPDMDEVINS pDevIns = pVGAState->pDevInsR3;
1053 PVM pVM = PDMDevHlpGetVM(pDevIns);
1054
1055 pBody->pVM = pVM;
1056 pBody->pvVRAM = pVGAState->vram_ptrR3;
1057 pBody->cbVRAM = pVGAState->vram_size;
1058
1059 rc = vbvaVHWAHHCommandPost(pVGAState, pCmd);
1060 AssertRC(rc);
1061 if(RT_SUCCESS(rc))
1062 {
1063 rc = pCmd->rc;
1064 AssertMsg(RT_SUCCESS(rc) || rc == VERR_NOT_IMPLEMENTED, ("%Rrc\n", rc));
1065 if(rc == VERR_NOT_IMPLEMENTED)
1066 {
1067 /* @todo: set some flag in pVGAState indicating VHWA is not supported */
1068 /* VERR_NOT_IMPLEMENTED is not a failure, we just do not support it */
1069 rc = VINF_SUCCESS;
1070 }
1071
1072 if (!RT_SUCCESS(rc))
1073 break;
1074 }
1075 else
1076 break;
1077
1078 ++iDisplay;
1079 if (iDisplay >= pVGAState->cMonitors)
1080 break;
1081 vbvaVHWAHHCommandReinit(pCmd, VBOXVHWACMD_TYPE_HH_CONSTRUCT, (int32_t)iDisplay);
1082 } while (true);
1083
1084 vbvaVHWAHHCommandRelease(pCmd);
1085
1086 return rc;
1087 }
1088 return VERR_OUT_OF_RESOURCES;
1089}
1090
1091int vbvaVHWAReset (PVGASTATE pVGAState)
1092{
1093 vbvaVHWACommandCClearAllPending(pVGAState);
1094
1095 /* ensure we have all pending cmds processed and h->g cmds disabled */
1096 VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(pVGAState, VBOXVHWACMD_TYPE_HH_RESET, 0, 0);
1097 Assert(pCmd);
1098 if(pCmd)
1099 {
1100 int rc = VINF_SUCCESS;
1101 uint32_t iDisplay = 0;
1102
1103 do
1104 {
1105 rc =vbvaVHWAHHCommandPost(pVGAState, pCmd);
1106 AssertRC(rc);
1107 if(RT_SUCCESS(rc))
1108 {
1109 rc = pCmd->rc;
1110 AssertMsg(RT_SUCCESS(rc) || rc == VERR_NOT_IMPLEMENTED, ("%Rrc\n", rc));
1111 if (rc == VERR_NOT_IMPLEMENTED)
1112 rc = VINF_SUCCESS;
1113 }
1114
1115 if (!RT_SUCCESS(rc))
1116 break;
1117
1118 ++iDisplay;
1119 if (iDisplay >= pVGAState->cMonitors)
1120 break;
1121 vbvaVHWAHHCommandReinit(pCmd, VBOXVHWACMD_TYPE_HH_RESET, (int32_t)iDisplay);
1122
1123 } while (true);
1124
1125 vbvaVHWAHHCommandRelease(pCmd);
1126
1127 return rc;
1128 }
1129 return VERR_OUT_OF_RESOURCES;
1130}
1131
1132typedef DECLCALLBACK(bool) FNVBOXVHWAHHCMDPRECB(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, void *pvContext);
1133typedef FNVBOXVHWAHHCMDPRECB *PFNVBOXVHWAHHCMDPRECB;
1134
1135typedef DECLCALLBACK(bool) FNVBOXVHWAHHCMDPOSTCB(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, int rc, void *pvContext);
1136typedef FNVBOXVHWAHHCMDPOSTCB *PFNVBOXVHWAHHCMDPOSTCB;
1137
1138int vbvaVHWAHHPost(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, PFNVBOXVHWAHHCMDPRECB pfnPre, PFNVBOXVHWAHHCMDPOSTCB pfnPost, void *pvContext)
1139{
1140 const VBOXVHWACMD_TYPE enmType = pCmd->enmCmd;
1141 int rc = VINF_SUCCESS;
1142 uint32_t iDisplay = 0;
1143
1144 do
1145 {
1146 if (!pfnPre || pfnPre(pVGAState, pCmd, iDisplay, pvContext))
1147 {
1148 rc = vbvaVHWAHHCommandPost(pVGAState, pCmd);
1149 AssertRC(rc);
1150 if (pfnPost)
1151 {
1152 if (!pfnPost(pVGAState, pCmd, iDisplay, rc, pvContext))
1153 {
1154 rc = VINF_SUCCESS;
1155 break;
1156 }
1157 rc = VINF_SUCCESS;
1158 }
1159 else if(RT_SUCCESS(rc))
1160 {
1161 rc = pCmd->rc;
1162 AssertMsg(RT_SUCCESS(rc) || rc == VERR_NOT_IMPLEMENTED, ("%Rrc\n", rc));
1163 if(rc == VERR_NOT_IMPLEMENTED)
1164 {
1165 rc = VINF_SUCCESS;
1166 }
1167 }
1168
1169 if (!RT_SUCCESS(rc))
1170 break;
1171 }
1172
1173 ++iDisplay;
1174 if (iDisplay >= pVGAState->cMonitors)
1175 break;
1176 vbvaVHWAHHCommandReinit(pCmd, enmType, (int32_t)iDisplay);
1177 } while (true);
1178
1179 return rc;
1180}
1181
1182/* @todo call this also on reset? */
1183int vbvaVHWAEnable (PVGASTATE pVGAState, bool bEnable)
1184{
1185 const VBOXVHWACMD_TYPE enmType = bEnable ? VBOXVHWACMD_TYPE_HH_ENABLE : VBOXVHWACMD_TYPE_HH_DISABLE;
1186 VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(pVGAState,
1187 enmType,
1188 0, 0);
1189 Assert(pCmd);
1190 if(pCmd)
1191 {
1192 int rc = vbvaVHWAHHPost (pVGAState, pCmd, NULL, NULL, NULL);
1193 vbvaVHWAHHCommandRelease(pCmd);
1194 return rc;
1195 }
1196 return VERR_OUT_OF_RESOURCES;
1197}
1198
1199int vboxVBVASaveStatePrep (PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1200{
1201 /* ensure we have no pending commands */
1202 return vbvaVHWAEnable(PDMINS_2_DATA(pDevIns, PVGASTATE), false);
1203}
1204
1205int vboxVBVASaveStateDone (PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1206{
1207 /* ensure we have no pending commands */
1208 return vbvaVHWAEnable(PDMINS_2_DATA(pDevIns, PVGASTATE), true);
1209}
1210
1211int vbvaVHWACommandCompleteAsynch(PPDMIDISPLAYVBVACALLBACKS pInterface, PVBOXVHWACMD pCmd)
1212{
1213 int rc;
1214 Log(("VGA Command <<< Async rc %d %#p, %d\n", pCmd->rc, pCmd, pCmd->enmCmd));
1215
1216 if((pCmd->Flags & VBOXVHWACMD_FLAG_HH_CMD) == 0)
1217 {
1218 PVGASTATE pVGAState = PPDMIDISPLAYVBVACALLBACKS_2_PVGASTATE(pInterface);
1219 PHGSMIINSTANCE pIns = pVGAState->pHGSMI;
1220
1221 Assert(pCmd->Flags & VBOXVHWACMD_FLAG_HG_ASYNCH);
1222#ifdef VBOX_WITH_WDDM
1223 if (pVGAState->fGuestCaps & VBVACAPS_COMPLETEGCMD_BY_IOREAD)
1224 {
1225 rc = HGSMICompleteGuestCommand(pIns, pCmd, !!(pCmd->Flags & VBOXVHWACMD_FLAG_GH_ASYNCH_IRQ));
1226 AssertRC(rc);
1227 }
1228 else
1229#endif
1230 {
1231 VBVAHOSTCMD *pHostCmd;
1232 int32_t iDisplay = pCmd->iDisplay;
1233
1234 if(pCmd->Flags & VBOXVHWACMD_FLAG_GH_ASYNCH_EVENT)
1235 {
1236 rc = HGSMIHostCommandAlloc (pIns,
1237 (void**)&pHostCmd,
1238 VBVAHOSTCMD_SIZE(sizeof(VBVAHOSTCMDEVENT)),
1239 HGSMI_CH_VBVA,
1240 VBVAHG_EVENT);
1241 AssertRC(rc);
1242 if(RT_SUCCESS(rc))
1243 {
1244 memset(pHostCmd, 0 , VBVAHOSTCMD_SIZE(sizeof(VBVAHOSTCMDEVENT)));
1245 pHostCmd->iDstID = pCmd->iDisplay;
1246 pHostCmd->customOpCode = 0;
1247 VBVAHOSTCMDEVENT *pBody = VBVAHOSTCMD_BODY(pHostCmd, VBVAHOSTCMDEVENT);
1248 pBody->pEvent = pCmd->GuestVBVAReserved1;
1249 }
1250 }
1251 else
1252 {
1253 HGSMIOFFSET offCmd = HGSMIPointerToOffsetHost (pIns, pCmd);
1254 Assert(offCmd != HGSMIOFFSET_VOID);
1255 if(offCmd != HGSMIOFFSET_VOID)
1256 {
1257 rc = HGSMIHostCommandAlloc (pIns,
1258 (void**)&pHostCmd,
1259 VBVAHOSTCMD_SIZE(sizeof(VBVAHOSTCMDVHWACMDCOMPLETE)),
1260 HGSMI_CH_VBVA,
1261 VBVAHG_DISPLAY_CUSTOM);
1262 AssertRC(rc);
1263 if(RT_SUCCESS(rc))
1264 {
1265 memset(pHostCmd, 0 , VBVAHOSTCMD_SIZE(sizeof(VBVAHOSTCMDVHWACMDCOMPLETE)));
1266 pHostCmd->iDstID = pCmd->iDisplay;
1267 pHostCmd->customOpCode = VBVAHG_DCUSTOM_VHWA_CMDCOMPLETE;
1268 VBVAHOSTCMDVHWACMDCOMPLETE *pBody = VBVAHOSTCMD_BODY(pHostCmd, VBVAHOSTCMDVHWACMDCOMPLETE);
1269 pBody->offCmd = offCmd;
1270 }
1271 }
1272 else
1273 {
1274 rc = VERR_INVALID_PARAMETER;
1275 }
1276 }
1277
1278 if(RT_SUCCESS(rc))
1279 {
1280 rc = HGSMIHostCommandProcessAndFreeAsynch(pIns, pHostCmd, (pCmd->Flags & VBOXVHWACMD_FLAG_GH_ASYNCH_IRQ) != 0);
1281 AssertRC(rc);
1282 if(RT_SUCCESS(rc))
1283 {
1284 return rc;
1285 }
1286 HGSMIHostCommandFree (pIns, pHostCmd);
1287 }
1288 }
1289 }
1290 else
1291 {
1292 PFNVBOXVHWA_HH_CALLBACK pfn = VBOXVHWA_HH_CALLBACK_GET(pCmd);
1293 if(pfn)
1294 {
1295 pfn(VBOXVHWA_HH_CALLBACK_GET_ARG(pCmd));
1296 }
1297 rc = VINF_SUCCESS;
1298 }
1299 return rc;
1300}
1301
1302typedef struct VBOXVBVASAVEDSTATECBDATA
1303{
1304 PSSMHANDLE pSSM;
1305 int rc;
1306 bool ab2DOn[VBOX_VIDEO_MAX_SCREENS];
1307} VBOXVBVASAVEDSTATECBDATA, *PVBOXVBVASAVEDSTATECBDATA;
1308
1309static DECLCALLBACK(bool) vboxVBVASaveStateBeginPostCb(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, int rc, void *pvContext)
1310{
1311 PVBOXVBVASAVEDSTATECBDATA pData = (PVBOXVBVASAVEDSTATECBDATA)pvContext;
1312 if (RT_FAILURE(pData->rc))
1313 return false;
1314 if (RT_FAILURE(rc))
1315 {
1316 pData->rc = rc;
1317 return false;
1318 }
1319
1320 Assert(iDisplay < RT_ELEMENTS(pData->ab2DOn));
1321 if (iDisplay >= RT_ELEMENTS(pData->ab2DOn))
1322 {
1323 pData->rc = VERR_INVALID_PARAMETER;
1324 return false;
1325 }
1326
1327 Assert(RT_SUCCESS(pCmd->rc) || pCmd->rc == VERR_NOT_IMPLEMENTED);
1328 if (RT_SUCCESS(pCmd->rc))
1329 {
1330 pData->ab2DOn[iDisplay] = true;
1331 }
1332 else if (pCmd->rc != VERR_NOT_IMPLEMENTED)
1333 {
1334 pData->rc = pCmd->rc;
1335 return false;
1336 }
1337
1338 return true;
1339}
1340
1341static DECLCALLBACK(bool) vboxVBVASaveStatePerformPreCb(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, void *pvContext)
1342{
1343 PVBOXVBVASAVEDSTATECBDATA pData = (PVBOXVBVASAVEDSTATECBDATA)pvContext;
1344 if (RT_FAILURE(pData->rc))
1345 return false;
1346
1347 Assert(iDisplay < RT_ELEMENTS(pData->ab2DOn));
1348 if (iDisplay >= RT_ELEMENTS(pData->ab2DOn))
1349 {
1350 pData->rc = VERR_INVALID_PARAMETER;
1351 return false;
1352 }
1353
1354 int rc;
1355
1356 if (pData->ab2DOn[iDisplay])
1357 {
1358 rc = SSMR3PutU32 (pData->pSSM, VBOXVBVASAVEDSTATE_VHWAAVAILABLE_MAGIC); AssertRC(rc);
1359 if (RT_FAILURE(rc))
1360 {
1361 pData->rc = rc;
1362 return false;
1363 }
1364 return true;
1365 }
1366
1367 rc = SSMR3PutU32 (pData->pSSM, VBOXVBVASAVEDSTATE_VHWAUNAVAILABLE_MAGIC); AssertRC(rc);
1368 if (RT_FAILURE(rc))
1369 {
1370 pData->rc = rc;
1371 return false;
1372 }
1373
1374 return false;
1375}
1376
1377static DECLCALLBACK(bool) vboxVBVASaveStateEndPreCb(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, void *pvContext)
1378{
1379 PVBOXVBVASAVEDSTATECBDATA pData = (PVBOXVBVASAVEDSTATECBDATA)pvContext;
1380 Assert(iDisplay < RT_ELEMENTS(pData->ab2DOn));
1381 if (pData->ab2DOn[iDisplay])
1382 {
1383 return true;
1384 }
1385
1386 return false;
1387}
1388
1389static DECLCALLBACK(bool) vboxVBVALoadStatePerformPostCb(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, int rc, void *pvContext)
1390{
1391 PVBOXVBVASAVEDSTATECBDATA pData = (PVBOXVBVASAVEDSTATECBDATA)pvContext;
1392 if (RT_FAILURE(pData->rc))
1393 return false;
1394 if (RT_FAILURE(rc))
1395 {
1396 pData->rc = rc;
1397 return false;
1398 }
1399
1400 Assert(iDisplay < RT_ELEMENTS(pData->ab2DOn));
1401 if (iDisplay >= RT_ELEMENTS(pData->ab2DOn))
1402 {
1403 pData->rc = VERR_INVALID_PARAMETER;
1404 return false;
1405 }
1406
1407 Assert(RT_SUCCESS(pCmd->rc) || pCmd->rc == VERR_NOT_IMPLEMENTED);
1408 if (pCmd->rc == VERR_NOT_IMPLEMENTED)
1409 {
1410 pData->rc = SSMR3SkipToEndOfUnit(pData->pSSM);
1411 AssertRC(pData->rc);
1412 return false;
1413 }
1414 if (RT_FAILURE(pCmd->rc))
1415 {
1416 pData->rc = pCmd->rc;
1417 return false;
1418 }
1419
1420 return true;
1421}
1422
1423static DECLCALLBACK(bool) vboxVBVALoadStatePerformPreCb(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, void *pvContext)
1424{
1425 PVBOXVBVASAVEDSTATECBDATA pData = (PVBOXVBVASAVEDSTATECBDATA)pvContext;
1426 if (RT_FAILURE(pData->rc))
1427 return false;
1428
1429 Assert(iDisplay < RT_ELEMENTS(pData->ab2DOn));
1430 if (iDisplay >= RT_ELEMENTS(pData->ab2DOn))
1431 {
1432 pData->rc = VERR_INVALID_PARAMETER;
1433 return false;
1434 }
1435
1436 int rc;
1437 uint32_t u32;
1438 rc = SSMR3GetU32(pData->pSSM, &u32); AssertRC(rc);
1439 if (RT_FAILURE(rc))
1440 {
1441 pData->rc = rc;
1442 return false;
1443 }
1444
1445 switch (u32)
1446 {
1447 case VBOXVBVASAVEDSTATE_VHWAAVAILABLE_MAGIC:
1448 return true;
1449 case VBOXVBVASAVEDSTATE_VHWAUNAVAILABLE_MAGIC:
1450 return false;
1451 default:
1452 pData->rc = VERR_INVALID_STATE;
1453 return false;
1454 }
1455}
1456#endif /* #ifdef VBOX_WITH_VIDEOHWACCEL */
1457
1458int vboxVBVASaveDevStateExec (PVGASTATE pVGAState, PSSMHANDLE pSSM)
1459{
1460 PHGSMIINSTANCE pIns = pVGAState->pHGSMI;
1461 int rc = HGSMIHostSaveStateExec (pIns, pSSM);
1462 if (RT_SUCCESS(rc))
1463 {
1464 /* Save VBVACONTEXT. */
1465 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pIns);
1466
1467 if (!pCtx)
1468 {
1469 AssertFailed();
1470
1471 /* Still write a valid value to the SSM. */
1472 rc = SSMR3PutU32 (pSSM, 0);
1473 AssertRCReturn(rc, rc);
1474 }
1475 else
1476 {
1477#ifdef DEBUG_sunlover
1478 dumpctx(pCtx);
1479#endif
1480
1481 rc = SSMR3PutU32 (pSSM, pCtx->cViews);
1482 AssertRCReturn(rc, rc);
1483
1484 uint32_t iView;
1485 for (iView = 0; iView < pCtx->cViews; iView++)
1486 {
1487 VBVAVIEW *pView = &pCtx->aViews[iView];
1488
1489 rc = SSMR3PutU32 (pSSM, pView->view.u32ViewIndex);
1490 AssertRCReturn(rc, rc);
1491 rc = SSMR3PutU32 (pSSM, pView->view.u32ViewOffset);
1492 AssertRCReturn(rc, rc);
1493 rc = SSMR3PutU32 (pSSM, pView->view.u32ViewSize);
1494 AssertRCReturn(rc, rc);
1495 rc = SSMR3PutU32 (pSSM, pView->view.u32MaxScreenSize);
1496 AssertRCReturn(rc, rc);
1497
1498 rc = SSMR3PutU32 (pSSM, pView->screen.u32ViewIndex);
1499 AssertRCReturn(rc, rc);
1500 rc = SSMR3PutS32 (pSSM, pView->screen.i32OriginX);
1501 AssertRCReturn(rc, rc);
1502 rc = SSMR3PutS32 (pSSM, pView->screen.i32OriginY);
1503 AssertRCReturn(rc, rc);
1504 rc = SSMR3PutU32 (pSSM, pView->screen.u32StartOffset);
1505 AssertRCReturn(rc, rc);
1506 rc = SSMR3PutU32 (pSSM, pView->screen.u32LineSize);
1507 AssertRCReturn(rc, rc);
1508 rc = SSMR3PutU32 (pSSM, pView->screen.u32Width);
1509 AssertRCReturn(rc, rc);
1510 rc = SSMR3PutU32 (pSSM, pView->screen.u32Height);
1511 AssertRCReturn(rc, rc);
1512 rc = SSMR3PutU16 (pSSM, pView->screen.u16BitsPerPixel);
1513 AssertRCReturn(rc, rc);
1514 rc = SSMR3PutU16 (pSSM, pView->screen.u16Flags);
1515 AssertRCReturn(rc, rc);
1516
1517 rc = SSMR3PutU32 (pSSM, pView->pVBVA? pView->u32VBVAOffset: HGSMIOFFSET_VOID);
1518 AssertRCReturn(rc, rc);
1519
1520 rc = SSMR3PutU32 (pSSM, pView->partialRecord.cb);
1521 AssertRCReturn(rc, rc);
1522
1523 if (pView->partialRecord.cb > 0)
1524 {
1525 rc = SSMR3PutMem (pSSM, pView->partialRecord.pu8, pView->partialRecord.cb);
1526 AssertRCReturn(rc, rc);
1527 }
1528 }
1529
1530 /* Save mouse pointer shape information. */
1531 rc = SSMR3PutBool (pSSM, pCtx->mouseShapeInfo.fSet);
1532 AssertRCReturn(rc, rc);
1533 rc = SSMR3PutBool (pSSM, pCtx->mouseShapeInfo.fVisible);
1534 AssertRCReturn(rc, rc);
1535 rc = SSMR3PutBool (pSSM, pCtx->mouseShapeInfo.fAlpha);
1536 AssertRCReturn(rc, rc);
1537 rc = SSMR3PutU32 (pSSM, pCtx->mouseShapeInfo.u32HotX);
1538 AssertRCReturn(rc, rc);
1539 rc = SSMR3PutU32 (pSSM, pCtx->mouseShapeInfo.u32HotY);
1540 AssertRCReturn(rc, rc);
1541 rc = SSMR3PutU32 (pSSM, pCtx->mouseShapeInfo.u32Width);
1542 AssertRCReturn(rc, rc);
1543 rc = SSMR3PutU32 (pSSM, pCtx->mouseShapeInfo.u32Height);
1544 AssertRCReturn(rc, rc);
1545 rc = SSMR3PutU32 (pSSM, pCtx->mouseShapeInfo.cbShape);
1546 AssertRCReturn(rc, rc);
1547 if (pCtx->mouseShapeInfo.cbShape)
1548 {
1549 rc = SSMR3PutMem (pSSM, pCtx->mouseShapeInfo.pu8Shape, pCtx->mouseShapeInfo.cbShape);
1550 AssertRCReturn(rc, rc);
1551 }
1552
1553#ifdef VBOX_WITH_WDDM
1554 /* Size of some additional data. For future extensions. */
1555 rc = SSMR3PutU32 (pSSM, 4);
1556 AssertRCReturn(rc, rc);
1557 rc = SSMR3PutU32 (pSSM, pVGAState->fGuestCaps);
1558 AssertRCReturn(rc, rc);
1559#else
1560 /* Size of some additional data. For future extensions. */
1561 rc = SSMR3PutU32 (pSSM, 0);
1562 AssertRCReturn(rc, rc);
1563#endif
1564 }
1565 }
1566
1567 return rc;
1568}
1569
1570int vboxVBVASaveStateExec (PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1571{
1572 PVGASTATE pVGAState = PDMINS_2_DATA(pDevIns, PVGASTATE);
1573 int rc;
1574#ifdef VBOX_WITH_VIDEOHWACCEL
1575 VBOXVBVASAVEDSTATECBDATA VhwaData = {0};
1576 VhwaData.pSSM = pSSM;
1577 uint32_t cbCmd = sizeof (VBOXVHWACMD_HH_SAVESTATE_SAVEPERFORM); /* maximum cmd size */
1578 VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(pVGAState, VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEBEGIN, 0, cbCmd);
1579 Assert(pCmd);
1580 if(pCmd)
1581 {
1582 vbvaVHWAHHPost (pVGAState, pCmd, NULL, vboxVBVASaveStateBeginPostCb, &VhwaData);
1583 rc = VhwaData.rc;
1584 AssertRC(rc);
1585 if (RT_SUCCESS(rc))
1586 {
1587#endif
1588 rc = vboxVBVASaveDevStateExec (pVGAState, pSSM);
1589 AssertRC(rc);
1590#ifdef VBOX_WITH_VIDEOHWACCEL
1591 if (RT_SUCCESS(rc))
1592 {
1593 vbvaVHWAHHCommandReinit(pCmd, VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEPERFORM, 0);
1594 VBOXVHWACMD_HH_SAVESTATE_SAVEPERFORM *pSave = VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_HH_SAVESTATE_SAVEPERFORM);
1595 pSave->pSSM = pSSM;
1596 vbvaVHWAHHPost (pVGAState, pCmd, vboxVBVASaveStatePerformPreCb, NULL, &VhwaData);
1597 rc = VhwaData.rc;
1598 AssertRC(rc);
1599 if (RT_SUCCESS(rc))
1600 {
1601 rc = vbvaVHWACommandSavePending(pVGAState, pSSM);
1602 AssertRCReturn(rc, rc);
1603
1604 vbvaVHWAHHCommandReinit(pCmd, VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEEND, 0);
1605 vbvaVHWAHHPost (pVGAState, pCmd, vboxVBVASaveStateEndPreCb, NULL, &VhwaData);
1606 rc = VhwaData.rc;
1607 AssertRC(rc);
1608 }
1609 }
1610 }
1611
1612 vbvaVHWAHHCommandRelease(pCmd);
1613 }
1614 else
1615 rc = VERR_OUT_OF_RESOURCES;
1616#else
1617 if (RT_SUCCESS(rc))
1618 {
1619 for (uint32_t i = 0; i < pVGAState->cMonitors; ++i)
1620 {
1621 rc = SSMR3PutU32 (pSSM, VBOXVBVASAVEDSTATE_VHWAUNAVAILABLE_MAGIC);
1622 AssertRCReturn(rc, rc);
1623 }
1624 }
1625#endif
1626 return rc;
1627}
1628
1629int vboxVBVALoadStateExec (PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t u32Version)
1630{
1631 if (u32Version < VGA_SAVEDSTATE_VERSION_HGSMI)
1632 {
1633 /* Nothing was saved. */
1634 return VINF_SUCCESS;
1635 }
1636
1637 PVGASTATE pVGAState = PDMINS_2_DATA(pDevIns, PVGASTATE);
1638 PHGSMIINSTANCE pIns = pVGAState->pHGSMI;
1639 int rc = HGSMIHostLoadStateExec (pIns, pSSM, u32Version);
1640 if (RT_SUCCESS(rc))
1641 {
1642 /* Load VBVACONTEXT. */
1643 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pIns);
1644
1645 if (!pCtx)
1646 {
1647 /* This should not happen. */
1648 AssertFailed();
1649 rc = VERR_INVALID_PARAMETER;
1650 }
1651 else
1652 {
1653 uint32_t cViews = 0;
1654 rc = SSMR3GetU32 (pSSM, &cViews);
1655 AssertRCReturn(rc, rc);
1656
1657 uint32_t iView;
1658 for (iView = 0; iView < cViews; iView++)
1659 {
1660 VBVAVIEW *pView = &pCtx->aViews[iView];
1661
1662 rc = SSMR3GetU32 (pSSM, &pView->view.u32ViewIndex);
1663 AssertRCReturn(rc, rc);
1664 rc = SSMR3GetU32 (pSSM, &pView->view.u32ViewOffset);
1665 AssertRCReturn(rc, rc);
1666 rc = SSMR3GetU32 (pSSM, &pView->view.u32ViewSize);
1667 AssertRCReturn(rc, rc);
1668 rc = SSMR3GetU32 (pSSM, &pView->view.u32MaxScreenSize);
1669 AssertRCReturn(rc, rc);
1670
1671 rc = SSMR3GetU32 (pSSM, &pView->screen.u32ViewIndex);
1672 AssertRCReturn(rc, rc);
1673 rc = SSMR3GetS32 (pSSM, &pView->screen.i32OriginX);
1674 AssertRCReturn(rc, rc);
1675 rc = SSMR3GetS32 (pSSM, &pView->screen.i32OriginY);
1676 AssertRCReturn(rc, rc);
1677 rc = SSMR3GetU32 (pSSM, &pView->screen.u32StartOffset);
1678 AssertRCReturn(rc, rc);
1679 rc = SSMR3GetU32 (pSSM, &pView->screen.u32LineSize);
1680 AssertRCReturn(rc, rc);
1681 rc = SSMR3GetU32 (pSSM, &pView->screen.u32Width);
1682 AssertRCReturn(rc, rc);
1683 rc = SSMR3GetU32 (pSSM, &pView->screen.u32Height);
1684 AssertRCReturn(rc, rc);
1685 rc = SSMR3GetU16 (pSSM, &pView->screen.u16BitsPerPixel);
1686 AssertRCReturn(rc, rc);
1687 rc = SSMR3GetU16 (pSSM, &pView->screen.u16Flags);
1688 AssertRCReturn(rc, rc);
1689
1690 rc = SSMR3GetU32 (pSSM, &pView->u32VBVAOffset);
1691 AssertRCReturn(rc, rc);
1692
1693 rc = SSMR3GetU32 (pSSM, &pView->partialRecord.cb);
1694 AssertRCReturn(rc, rc);
1695
1696 if (pView->partialRecord.cb == 0)
1697 {
1698 pView->partialRecord.pu8 = NULL;
1699 }
1700 else
1701 {
1702 Assert(pView->partialRecord.pu8 == NULL); /* Should be it. */
1703
1704 uint8_t *pu8 = (uint8_t *)RTMemAlloc (pView->partialRecord.cb);
1705
1706 if (!pu8)
1707 {
1708 return VERR_NO_MEMORY;
1709 }
1710
1711 pView->partialRecord.pu8 = pu8;
1712
1713 rc = SSMR3GetMem (pSSM, pView->partialRecord.pu8, pView->partialRecord.cb);
1714 AssertRCReturn(rc, rc);
1715 }
1716
1717 if (pView->u32VBVAOffset == HGSMIOFFSET_VOID)
1718 {
1719 pView->pVBVA = NULL;
1720 }
1721 else
1722 {
1723 pView->pVBVA = (VBVABUFFER *)HGSMIOffsetToPointerHost (pIns, pView->u32VBVAOffset);
1724 }
1725 }
1726
1727 if (u32Version > VGA_SAVEDSTATE_VERSION_WITH_CONFIG)
1728 {
1729 /* Read mouse pointer shape information. */
1730 rc = SSMR3GetBool (pSSM, &pCtx->mouseShapeInfo.fSet);
1731 AssertRCReturn(rc, rc);
1732 rc = SSMR3GetBool (pSSM, &pCtx->mouseShapeInfo.fVisible);
1733 AssertRCReturn(rc, rc);
1734 rc = SSMR3GetBool (pSSM, &pCtx->mouseShapeInfo.fAlpha);
1735 AssertRCReturn(rc, rc);
1736 rc = SSMR3GetU32 (pSSM, &pCtx->mouseShapeInfo.u32HotX);
1737 AssertRCReturn(rc, rc);
1738 rc = SSMR3GetU32 (pSSM, &pCtx->mouseShapeInfo.u32HotY);
1739 AssertRCReturn(rc, rc);
1740 rc = SSMR3GetU32 (pSSM, &pCtx->mouseShapeInfo.u32Width);
1741 AssertRCReturn(rc, rc);
1742 rc = SSMR3GetU32 (pSSM, &pCtx->mouseShapeInfo.u32Height);
1743 AssertRCReturn(rc, rc);
1744 rc = SSMR3GetU32 (pSSM, &pCtx->mouseShapeInfo.cbShape);
1745 AssertRCReturn(rc, rc);
1746 if (pCtx->mouseShapeInfo.cbShape)
1747 {
1748 pCtx->mouseShapeInfo.pu8Shape = (uint8_t *)RTMemAlloc(pCtx->mouseShapeInfo.cbShape);
1749 if (pCtx->mouseShapeInfo.pu8Shape == NULL)
1750 {
1751 return VERR_NO_MEMORY;
1752 }
1753 pCtx->mouseShapeInfo.cbAllocated = pCtx->mouseShapeInfo.cbShape;
1754 rc = SSMR3GetMem (pSSM, pCtx->mouseShapeInfo.pu8Shape, pCtx->mouseShapeInfo.cbShape);
1755 AssertRCReturn(rc, rc);
1756 }
1757 else
1758 {
1759 pCtx->mouseShapeInfo.pu8Shape = NULL;
1760 }
1761
1762 /* Size of some additional data. For future extensions. */
1763 uint32_t cbExtra = 0;
1764 rc = SSMR3GetU32 (pSSM, &cbExtra);
1765 AssertRCReturn(rc, rc);
1766#ifdef VBOX_WITH_WDDM
1767 if (cbExtra >= 4)
1768 {
1769 rc = SSMR3GetU32 (pSSM, &pVGAState->fGuestCaps);
1770 AssertRCReturn(rc, rc);
1771 cbExtra -= 4;
1772 }
1773#endif
1774 if (cbExtra > 0)
1775 {
1776 rc = SSMR3Skip(pSSM, cbExtra);
1777 AssertRCReturn(rc, rc);
1778 }
1779 }
1780
1781 pCtx->cViews = iView;
1782 LogFlowFunc(("%d views loaded\n", pCtx->cViews));
1783
1784 if (u32Version > VGA_SAVEDSTATE_VERSION_WDDM)
1785 {
1786#ifdef VBOX_WITH_VIDEOHWACCEL
1787 uint32_t cbCmd = sizeof (VBOXVHWACMD_HH_SAVESTATE_LOADPERFORM); /* maximum cmd size */
1788 VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(pVGAState, VBOXVHWACMD_TYPE_HH_SAVESTATE_LOADPERFORM, 0, cbCmd);
1789 Assert(pCmd);
1790 if(pCmd)
1791 {
1792 VBOXVBVASAVEDSTATECBDATA VhwaData = {0};
1793 VhwaData.pSSM = pSSM;
1794 VBOXVHWACMD_HH_SAVESTATE_LOADPERFORM *pLoad = VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_HH_SAVESTATE_LOADPERFORM);
1795 pLoad->pSSM = pSSM;
1796 vbvaVHWAHHPost (pVGAState, pCmd, vboxVBVALoadStatePerformPreCb, vboxVBVALoadStatePerformPostCb, &VhwaData);
1797 rc = VhwaData.rc;
1798 vbvaVHWAHHCommandRelease(pCmd);
1799 AssertRCReturn(rc, rc);
1800
1801 rc = vbvaVHWACommandLoadPending(pVGAState, pSSM, u32Version);
1802 AssertRCReturn(rc, rc);
1803 }
1804 else
1805 {
1806 rc = VERR_OUT_OF_RESOURCES;
1807 }
1808#else
1809 rc = SSMR3SkipToEndOfUnit(pSSM);
1810 AssertRCReturn(rc, rc);
1811#endif
1812 }
1813
1814#ifdef DEBUG_sunlover
1815 dumpctx(pCtx);
1816#endif
1817 }
1818 }
1819
1820 return rc;
1821}
1822
1823int vboxVBVALoadStateDone (PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1824{
1825 PVGASTATE pVGAState = PDMINS_2_DATA(pDevIns, PVGASTATE);
1826 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pVGAState->pHGSMI);
1827
1828 if (pCtx)
1829 {
1830 uint32_t iView;
1831 for (iView = 0; iView < pCtx->cViews; iView++)
1832 {
1833 VBVAVIEW *pView = &pCtx->aViews[iView];
1834
1835 if (pView->pVBVA)
1836 {
1837 vbvaEnable (iView, pVGAState, pCtx, pView->pVBVA, pView->u32VBVAOffset, true /* fRestored */);
1838 vbvaResize (pVGAState, pView, &pView->screen);
1839 }
1840 }
1841
1842 if (pCtx->mouseShapeInfo.fSet)
1843 {
1844 vbvaUpdateMousePointerShape(pVGAState, &pCtx->mouseShapeInfo, true, pCtx->mouseShapeInfo.pu8Shape);
1845 }
1846 }
1847
1848 return VINF_SUCCESS;
1849}
1850
1851void VBVARaiseIrq (PVGASTATE pVGAState, uint32_t fFlags)
1852{
1853 PPDMDEVINS pDevIns = pVGAState->pDevInsR3;
1854 PDMCritSectEnter(&pVGAState->CritSect, VERR_SEM_BUSY);
1855
1856 HGSMISetHostGuestFlags(pVGAState->pHGSMI, HGSMIHOSTFLAGS_IRQ | fFlags);
1857 PDMDevHlpPCISetIrq(pDevIns, 0, PDM_IRQ_LEVEL_HIGH);
1858
1859 PDMCritSectLeave(&pVGAState->CritSect);
1860}
1861
1862/*
1863 *
1864 * New VBVA uses a new interface id: #define VBE_DISPI_ID_VBOX_VIDEO 0xBE01
1865 *
1866 * VBVA uses two 32 bits IO ports to write VRAM offsets of shared memory blocks for commands.
1867 * Read Write
1868 * Host port 0x3b0 to process completed
1869 * Guest port 0x3d0 control value? to process
1870 *
1871 */
1872
1873static DECLCALLBACK(void) vbvaNotifyGuest (void *pvCallback)
1874{
1875#if defined(VBOX_WITH_HGSMI) && (defined(VBOX_WITH_VIDEOHWACCEL) || defined(VBOX_WITH_VDMA) || defined(VBOX_WITH_WDDM))
1876 PVGASTATE pVGAState = (PVGASTATE)pvCallback;
1877 VBVARaiseIrq (pVGAState, 0);
1878#else
1879 NOREF(pvCallback);
1880 /* Do nothing. Later the VMMDev/VGA IRQ can be used for the notification. */
1881#endif
1882}
1883
1884/* The guest submitted a buffer. @todo Verify all guest data. */
1885static DECLCALLBACK(int) vbvaChannelHandler (void *pvHandler, uint16_t u16ChannelInfo, void *pvBuffer, HGSMISIZE cbBuffer)
1886{
1887 int rc = VINF_SUCCESS;
1888
1889 LogFlowFunc(("pvHandler %p, u16ChannelInfo %d, pvBuffer %p, cbBuffer %u\n",
1890 pvHandler, u16ChannelInfo, pvBuffer, cbBuffer));
1891
1892 PVGASTATE pVGAState = (PVGASTATE)pvHandler;
1893 PHGSMIINSTANCE pIns = pVGAState->pHGSMI;
1894 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pIns);
1895
1896 switch (u16ChannelInfo)
1897 {
1898#ifdef VBOX_WITH_VDMA
1899 case VBVA_VDMA_CMD:
1900 {
1901 if (cbBuffer < VBoxSHGSMIBufferHeaderSize() + sizeof (VBOXVDMACBUF_DR))
1902 {
1903 rc = VERR_INVALID_PARAMETER;
1904 break;
1905 }
1906 PVBOXVDMACBUF_DR pCmd = (PVBOXVDMACBUF_DR)VBoxSHGSMIBufferData ((PVBOXSHGSMIHEADER)pvBuffer);
1907 vboxVDMACommand(pVGAState->pVdma, pCmd, cbBuffer - VBoxSHGSMIBufferHeaderSize());
1908 rc = VINF_SUCCESS;
1909 break;
1910 }
1911 case VBVA_VDMA_CTL:
1912 {
1913 if (cbBuffer < VBoxSHGSMIBufferHeaderSize() + sizeof (VBOXVDMA_CTL))
1914 {
1915 rc = VERR_INVALID_PARAMETER;
1916 break;
1917 }
1918 PVBOXVDMA_CTL pCmd = (PVBOXVDMA_CTL)VBoxSHGSMIBufferData ((PVBOXSHGSMIHEADER)pvBuffer);
1919 vboxVDMAControl(pVGAState->pVdma, pCmd, cbBuffer - VBoxSHGSMIBufferHeaderSize());
1920 rc = VINF_SUCCESS;
1921 break;
1922 }
1923#endif
1924 case VBVA_QUERY_CONF32:
1925 {
1926 if (cbBuffer < sizeof (VBVACONF32))
1927 {
1928 rc = VERR_INVALID_PARAMETER;
1929 break;
1930 }
1931
1932 VBVACONF32 *pConf32 = (VBVACONF32 *)pvBuffer;
1933 LogFlowFunc(("VBVA_QUERY_CONF32: u32Index %d, u32Value 0x%x\n",
1934 pConf32->u32Index, pConf32->u32Value));
1935
1936 if (pConf32->u32Index == VBOX_VBVA_CONF32_MONITOR_COUNT)
1937 {
1938 pConf32->u32Value = pCtx->cViews;
1939 }
1940 else if (pConf32->u32Index == VBOX_VBVA_CONF32_HOST_HEAP_SIZE)
1941 {
1942 /* @todo a value calculated from the vram size */
1943 pConf32->u32Value = 64*_1K;
1944 }
1945 else
1946 {
1947 Log(("Unsupported VBVA_QUERY_CONF32 index %d!!!\n",
1948 pConf32->u32Index));
1949 rc = VERR_INVALID_PARAMETER;
1950 }
1951 } break;
1952
1953 case VBVA_SET_CONF32:
1954 {
1955 if (cbBuffer < sizeof (VBVACONF32))
1956 {
1957 rc = VERR_INVALID_PARAMETER;
1958 break;
1959 }
1960
1961 VBVACONF32 *pConf32 = (VBVACONF32 *)pvBuffer;
1962 LogFlowFunc(("VBVA_SET_CONF32: u32Index %d, u32Value 0x%x\n",
1963 pConf32->u32Index, pConf32->u32Value));
1964
1965 if (pConf32->u32Index == VBOX_VBVA_CONF32_MONITOR_COUNT)
1966 {
1967 /* do nothing. this is a const. */
1968 }
1969 else if (pConf32->u32Index == VBOX_VBVA_CONF32_HOST_HEAP_SIZE)
1970 {
1971 /* do nothing. this is a const. */
1972 }
1973 else
1974 {
1975 Log(("Unsupported VBVA_SET_CONF32 index %d!!!\n",
1976 pConf32->u32Index));
1977 rc = VERR_INVALID_PARAMETER;
1978 }
1979 } break;
1980
1981 case VBVA_INFO_VIEW:
1982 {
1983 if (cbBuffer < sizeof (VBVAINFOVIEW))
1984 {
1985 rc = VERR_INVALID_PARAMETER;
1986 break;
1987 }
1988
1989 /* Guest submits an array of VBVAINFOVIEW structures. */
1990 VBVAINFOVIEW *pView = (VBVAINFOVIEW *)pvBuffer;
1991
1992 for (;
1993 cbBuffer >= sizeof (VBVAINFOVIEW);
1994 pView++, cbBuffer -= sizeof (VBVAINFOVIEW))
1995 {
1996 LogFlowFunc(("VBVA_INFO_VIEW: index %d, offset 0x%x, size 0x%x, max screen size 0x%x\n",
1997 pView->u32ViewIndex, pView->u32ViewOffset, pView->u32ViewSize, pView->u32MaxScreenSize));
1998
1999 /* @todo verify view data. */
2000 if (pView->u32ViewIndex >= pCtx->cViews)
2001 {
2002 Log(("View index too large %d!!!\n",
2003 pView->u32ViewIndex));
2004 rc = VERR_INVALID_PARAMETER;
2005 break;
2006 }
2007
2008 pCtx->aViews[pView->u32ViewIndex].view = *pView;
2009 }
2010 } break;
2011
2012 case VBVA_INFO_HEAP:
2013 {
2014 if (cbBuffer < sizeof (VBVAINFOHEAP))
2015 {
2016 rc = VERR_INVALID_PARAMETER;
2017 break;
2018 }
2019
2020 VBVAINFOHEAP *pHeap = (VBVAINFOHEAP *)pvBuffer;
2021 LogFlowFunc(("VBVA_INFO_HEAP: offset 0x%x, size 0x%x\n",
2022 pHeap->u32HeapOffset, pHeap->u32HeapSize));
2023
2024 rc = HGSMISetupHostHeap (pIns, pHeap->u32HeapOffset, pHeap->u32HeapSize);
2025 } break;
2026
2027 case VBVA_FLUSH:
2028 {
2029 if (cbBuffer < sizeof (VBVAFLUSH))
2030 {
2031 rc = VERR_INVALID_PARAMETER;
2032 break;
2033 }
2034
2035 VBVAFLUSH *pFlush = (VBVAFLUSH *)pvBuffer;
2036 LogFlowFunc(("VBVA_FLUSH: u32Reserved 0x%x\n",
2037 pFlush->u32Reserved));
2038
2039 rc = vbvaFlush (pVGAState, pCtx);
2040 } break;
2041
2042 case VBVA_INFO_SCREEN:
2043 {
2044 if (cbBuffer < sizeof (VBVAINFOSCREEN))
2045 {
2046 rc = VERR_INVALID_PARAMETER;
2047 break;
2048 }
2049
2050 VBVAINFOSCREEN *pScreen = (VBVAINFOSCREEN *)pvBuffer;
2051 VBVAINFOVIEW *pView = &pCtx->aViews[pScreen->u32ViewIndex].view;
2052 /* Calculate the offset of the end of the screen so we can make
2053 * sure it is inside the view. I assume that screen rollover is not
2054 * implemented. */
2055 int64_t offEnd = (int64_t)pScreen->u32Height * pScreen->u32LineSize
2056 + pScreen->u32Width + pScreen->u32StartOffset;
2057 LogRel(("VBVA_INFO_SCREEN: [%d] @%d,%d %dx%d, line 0x%x, BPP %d, flags 0x%x\n",
2058 pScreen->u32ViewIndex, pScreen->i32OriginX, pScreen->i32OriginY,
2059 pScreen->u32Width, pScreen->u32Height,
2060 pScreen->u32LineSize, pScreen->u16BitsPerPixel, pScreen->u16Flags));
2061
2062 if ( pScreen->u32ViewIndex < RT_ELEMENTS (pCtx->aViews)
2063 && pScreen->u16BitsPerPixel <= 32
2064 && pScreen->u32Width <= UINT16_MAX
2065 && pScreen->u32Height <= UINT16_MAX
2066 && pScreen->u32LineSize <= UINT16_MAX * 4
2067 && offEnd < pView->u32MaxScreenSize)
2068 {
2069 vbvaResize (pVGAState, &pCtx->aViews[pScreen->u32ViewIndex], pScreen);
2070 }
2071 else
2072 {
2073 LogRelFlow(("VBVA_INFO_SCREEN [%lu]: bad data: %lux%lu, line 0x%lx, BPP %u, start offset %lu, max screen size %lu\n",
2074 (unsigned long)pScreen->u32ViewIndex,
2075 (unsigned long)pScreen->u32Width,
2076 (unsigned long)pScreen->u32Height,
2077 (unsigned long)pScreen->u32LineSize,
2078 (unsigned long)pScreen->u16BitsPerPixel,
2079 (unsigned long)pScreen->u32StartOffset,
2080 (unsigned long)pView->u32MaxScreenSize));
2081 rc = VERR_INVALID_PARAMETER;
2082 }
2083 } break;
2084
2085 case VBVA_ENABLE:
2086 {
2087 if (cbBuffer < sizeof (VBVAENABLE))
2088 {
2089 rc = VERR_INVALID_PARAMETER;
2090 break;
2091 }
2092
2093 VBVAENABLE *pEnable = (VBVAENABLE *)pvBuffer;
2094 unsigned uScreenId;
2095 if (pEnable->u32Flags & VBVA_F_EXTENDED)
2096 {
2097 if (cbBuffer < sizeof (VBVAENABLE_EX))
2098 {
2099 rc = VERR_INVALID_PARAMETER;
2100 break;
2101 }
2102
2103 VBVAENABLE_EX *pEnableEx = (VBVAENABLE_EX *)pvBuffer;
2104 uScreenId = pEnableEx->u32ScreenId;
2105 }
2106 else
2107 {
2108 uScreenId = vbvaViewFromOffset (pIns, pCtx, pvBuffer);
2109 }
2110
2111 if (uScreenId == ~0U)
2112 {
2113 rc = VERR_INVALID_PARAMETER;
2114 break;
2115 }
2116
2117 LogFlowFunc(("VBVA_ENABLE[%d]: u32Flags 0x%x u32Offset 0x%x\n",
2118 uScreenId, pEnable->u32Flags, pEnable->u32Offset));
2119
2120 if ((pEnable->u32Flags & (VBVA_F_ENABLE | VBVA_F_DISABLE)) == VBVA_F_ENABLE)
2121 {
2122 /* Guest reported offset relative to view. */
2123 uint32_t u32Offset = pEnable->u32Offset;
2124 if (!(pEnable->u32Flags & VBVA_F_ABSOFFSET))
2125 {
2126 u32Offset += pCtx->aViews[uScreenId].view.u32ViewOffset;
2127 }
2128
2129 VBVABUFFER *pVBVA = (VBVABUFFER *)HGSMIOffsetToPointerHost (pIns, u32Offset);
2130
2131 if (pVBVA)
2132 {
2133 /* Process any pending orders and empty the VBVA ring buffer. */
2134 vbvaFlush (pVGAState, pCtx);
2135
2136 rc = vbvaEnable (uScreenId, pVGAState, pCtx, pVBVA, u32Offset, false /* fRestored */);
2137 }
2138 else
2139 {
2140 Log(("Invalid VBVABUFFER offset 0x%x!!!\n",
2141 pEnable->u32Offset));
2142 rc = VERR_INVALID_PARAMETER;
2143 }
2144 }
2145 else if ((pEnable->u32Flags & (VBVA_F_ENABLE | VBVA_F_DISABLE)) == VBVA_F_DISABLE)
2146 {
2147 rc = vbvaDisable (uScreenId, pVGAState, pCtx);
2148 }
2149 else
2150 {
2151 Log(("Invalid VBVA_ENABLE flags 0x%x!!!\n",
2152 pEnable->u32Flags));
2153 rc = VERR_INVALID_PARAMETER;
2154 }
2155
2156 pEnable->i32Result = rc;
2157 } break;
2158
2159 case VBVA_MOUSE_POINTER_SHAPE:
2160 {
2161 if (cbBuffer < sizeof (VBVAMOUSEPOINTERSHAPE))
2162 {
2163 rc = VERR_INVALID_PARAMETER;
2164 break;
2165 }
2166
2167 VBVAMOUSEPOINTERSHAPE *pShape = (VBVAMOUSEPOINTERSHAPE *)pvBuffer;
2168
2169 LogFlowFunc(("VBVA_MOUSE_POINTER_SHAPE: i32Result 0x%x, fu32Flags 0x%x, hot spot %d,%d, size %dx%d\n",
2170 pShape->i32Result,
2171 pShape->fu32Flags,
2172 pShape->u32HotX,
2173 pShape->u32HotY,
2174 pShape->u32Width,
2175 pShape->u32Height));
2176
2177 rc = vbvaMousePointerShape (pVGAState, pCtx, pShape, cbBuffer);
2178
2179 pShape->i32Result = rc;
2180 } break;
2181
2182
2183#ifdef VBOX_WITH_VIDEOHWACCEL
2184 case VBVA_VHWA_CMD:
2185 {
2186 if (cbBuffer < sizeof (VBOXVHWACMD))
2187 {
2188 rc = VERR_INVALID_PARAMETER;
2189 break;
2190 }
2191 vbvaVHWAHandleCommand(pVGAState, (PVBOXVHWACMD)pvBuffer);
2192 rc = VINF_SUCCESS;
2193 break;
2194 } break;
2195#endif
2196
2197#ifdef VBOX_WITH_WDDM
2198 case VBVA_INFO_CAPS:
2199 {
2200 if (cbBuffer < sizeof (VBVACAPS))
2201 {
2202 rc = VERR_INVALID_PARAMETER;
2203 break;
2204 }
2205
2206 VBVACAPS *pCaps = (VBVACAPS*)pvBuffer;
2207 pVGAState->fGuestCaps = pCaps->fCaps;
2208 pCaps->rc = VINF_SUCCESS;
2209 } break;
2210#endif
2211
2212 case VBVA_CMDVBVA_ENABLE:
2213 case VBVA_CMDVBVA_SUBMIT:
2214 case VBVA_CMDVBVA_FLUSH:
2215 {
2216 /* implement */
2217 } break;
2218
2219 case VBVA_SCANLINE_CFG:
2220 {
2221 if (cbBuffer < sizeof (VBVASCANLINECFG))
2222 {
2223 rc = VERR_INVALID_PARAMETER;
2224 break;
2225 }
2226
2227 VBVASCANLINECFG *pCfg = (VBVASCANLINECFG*)pvBuffer;
2228 pVGAState->fScanLineCfg = pCfg->fFlags;
2229 pCfg->rc = VINF_SUCCESS;
2230 } break;
2231 default:
2232 Log(("Unsupported VBVA guest command %d!!!\n",
2233 u16ChannelInfo));
2234 break;
2235 }
2236
2237 return rc;
2238}
2239
2240void VBVAReset (PVGASTATE pVGAState)
2241{
2242 if (!pVGAState || !pVGAState->pHGSMI)
2243 {
2244 return;
2245 }
2246
2247 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pVGAState->pHGSMI);
2248
2249#ifdef VBOX_WITH_VIDEOHWACCEL
2250 vbvaVHWAReset (pVGAState);
2251#endif
2252
2253 uint32_t HgFlags = HGSMIReset (pVGAState->pHGSMI);
2254 if(HgFlags & HGSMIHOSTFLAGS_IRQ)
2255 {
2256 /* this means the IRQ is LEVEL_HIGH, need to reset it */
2257 PDMDevHlpPCISetIrq(pVGAState->pDevInsR3, 0, PDM_IRQ_LEVEL_LOW);
2258 }
2259
2260 if (pCtx)
2261 {
2262 vbvaFlush (pVGAState, pCtx);
2263
2264 unsigned uScreenId;
2265
2266 for (uScreenId = 0; uScreenId < pCtx->cViews; uScreenId++)
2267 {
2268 vbvaDisable (uScreenId, pVGAState, pCtx);
2269 }
2270
2271 pCtx->mouseShapeInfo.fSet = false;
2272 RTMemFree(pCtx->mouseShapeInfo.pu8Shape);
2273 pCtx->mouseShapeInfo.pu8Shape = NULL;
2274 pCtx->mouseShapeInfo.cbAllocated = 0;
2275 pCtx->mouseShapeInfo.cbShape = 0;
2276 }
2277
2278}
2279
2280int VBVAUpdateDisplay (PVGASTATE pVGAState)
2281{
2282 int rc = VERR_NOT_SUPPORTED; /* Assuming that the VGA device will have to do updates. */
2283
2284 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pVGAState->pHGSMI);
2285
2286 if (pCtx)
2287 {
2288 rc = vbvaFlush (pVGAState, pCtx);
2289
2290 if (RT_SUCCESS (rc))
2291 {
2292 if (!pCtx->aViews[0].pVBVA)
2293 {
2294 /* VBVA is not enabled for the first view, so VGA device must do updates. */
2295 rc = VERR_NOT_SUPPORTED;
2296 }
2297 }
2298 }
2299
2300 return rc;
2301}
2302
2303static HGSMICHANNELHANDLER sOldChannelHandler;
2304
2305int VBVAInit (PVGASTATE pVGAState)
2306{
2307 PPDMDEVINS pDevIns = pVGAState->pDevInsR3;
2308
2309 PVM pVM = PDMDevHlpGetVM(pDevIns);
2310
2311 int rc = HGSMICreate (&pVGAState->pHGSMI,
2312 pVM,
2313 "VBVA",
2314 0,
2315 pVGAState->vram_ptrR3,
2316 pVGAState->vram_size,
2317 vbvaNotifyGuest,
2318 pVGAState,
2319 sizeof (VBVACONTEXT));
2320
2321 if (RT_SUCCESS (rc))
2322 {
2323 rc = HGSMIHostChannelRegister (pVGAState->pHGSMI,
2324 HGSMI_CH_VBVA,
2325 vbvaChannelHandler,
2326 pVGAState,
2327 &sOldChannelHandler);
2328 if (RT_SUCCESS (rc))
2329 {
2330 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pVGAState->pHGSMI);
2331 pCtx->cViews = pVGAState->cMonitors;
2332 }
2333 }
2334
2335 return rc;
2336
2337}
2338
2339void VBVADestroy (PVGASTATE pVGAState)
2340{
2341 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pVGAState->pHGSMI);
2342
2343 if (pCtx)
2344 {
2345 pCtx->mouseShapeInfo.fSet = false;
2346 RTMemFree(pCtx->mouseShapeInfo.pu8Shape);
2347 pCtx->mouseShapeInfo.pu8Shape = NULL;
2348 pCtx->mouseShapeInfo.cbAllocated = 0;
2349 pCtx->mouseShapeInfo.cbShape = 0;
2350 }
2351
2352 HGSMIDestroy (pVGAState->pHGSMI);
2353 pVGAState->pHGSMI = NULL;
2354}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette