VirtualBox

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

Last change on this file since 49983 was 49507, checked in by vboxsync, 11 years ago

vga/crOpenGL: basics for ring buffer-based command submission

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 77.8 KB
Line 
1/* $Id: DevVGA_VBVA.cpp 49507 2013-11-15 15:20:59Z 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.virtualbox.org. 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 if (pShape->u32Width > 8192 || pShape->u32Height > 8192)
633 {
634 Log(("vbvaMousePointerShape: unsupported size %ux%u\n",
635 pShape->u32Width, pShape->u32Height));
636 return VERR_INVALID_PARAMETER;
637 }
638
639 cbPointerData = ((((pShape->u32Width + 7) / 8) * pShape->u32Height + 3) & ~3)
640 + pShape->u32Width * 4 * pShape->u32Height;
641 }
642
643 if (cbPointerData > cbShape - RT_OFFSETOF(VBVAMOUSEPOINTERSHAPE, au8Data))
644 {
645 Log(("vbvaMousePointerShape: calculated pointer data size is too big (%d bytes, limit %d)\n",
646 cbPointerData, cbShape - RT_OFFSETOF(VBVAMOUSEPOINTERSHAPE, au8Data)));
647 return VERR_INVALID_PARAMETER;
648 }
649
650 /* Save mouse info it will be used to restore mouse pointer after restoring saved state. */
651 pCtx->mouseShapeInfo.fSet = true;
652 pCtx->mouseShapeInfo.fVisible = fVisible;
653 pCtx->mouseShapeInfo.fAlpha = fAlpha;
654 if (fShape)
655 {
656 /* Data related to shape. */
657 pCtx->mouseShapeInfo.u32HotX = pShape->u32HotX;
658 pCtx->mouseShapeInfo.u32HotY = pShape->u32HotY;
659 pCtx->mouseShapeInfo.u32Width = pShape->u32Width;
660 pCtx->mouseShapeInfo.u32Height = pShape->u32Height;
661
662 /* Reallocate memory buffer if necessary. */
663 if (cbPointerData > pCtx->mouseShapeInfo.cbAllocated)
664 {
665 RTMemFree (pCtx->mouseShapeInfo.pu8Shape);
666 pCtx->mouseShapeInfo.pu8Shape = NULL;
667 pCtx->mouseShapeInfo.cbShape = 0;
668
669 uint8_t *pu8Shape = (uint8_t *)RTMemAlloc (cbPointerData);
670 if (pu8Shape)
671 {
672 pCtx->mouseShapeInfo.pu8Shape = pu8Shape;
673 pCtx->mouseShapeInfo.cbAllocated = cbPointerData;
674 }
675 }
676
677 /* Copy shape bitmaps. */
678 if (pCtx->mouseShapeInfo.pu8Shape)
679 {
680 memcpy (pCtx->mouseShapeInfo.pu8Shape, &pShape->au8Data[0], cbPointerData);
681 pCtx->mouseShapeInfo.cbShape = cbPointerData;
682 }
683 }
684
685 if (pVGAState->pDrv->pfnVBVAMousePointerShape == NULL)
686 {
687 return VERR_NOT_SUPPORTED;
688 }
689
690 int rc = vbvaUpdateMousePointerShape(pVGAState, &pCtx->mouseShapeInfo, fShape, &pShape->au8Data[0]);
691
692 return rc;
693}
694
695static unsigned vbvaViewFromOffset (PHGSMIINSTANCE pIns, VBVACONTEXT *pCtx, const void *pvBuffer)
696{
697 /* Check which view contains the buffer. */
698 HGSMIOFFSET offBuffer = HGSMIPointerToOffsetHost (pIns, pvBuffer);
699
700 if (offBuffer != HGSMIOFFSET_VOID)
701 {
702 unsigned uScreenId;
703
704 for (uScreenId = 0; uScreenId < pCtx->cViews; uScreenId++)
705 {
706 VBVAINFOVIEW *pView = &pCtx->aViews[uScreenId].view;
707
708 if ( pView->u32ViewSize > 0
709 && pView->u32ViewOffset <= offBuffer
710 && offBuffer <= pView->u32ViewOffset + pView->u32ViewSize - 1)
711 {
712 return pView->u32ViewIndex;
713 }
714 }
715 }
716
717 return ~0U;
718}
719
720#ifdef DEBUG_sunlover
721static void dumpctx(const VBVACONTEXT *pCtx)
722{
723 Log(("VBVACONTEXT dump: cViews %d\n", pCtx->cViews));
724
725 uint32_t iView;
726 for (iView = 0; iView < pCtx->cViews; iView++)
727 {
728 const VBVAVIEW *pView = &pCtx->aViews[iView];
729
730 Log((" view %d o 0x%x s 0x%x m 0x%x\n",
731 pView->view.u32ViewIndex,
732 pView->view.u32ViewOffset,
733 pView->view.u32ViewSize,
734 pView->view.u32MaxScreenSize));
735
736 Log((" screen %d @%d,%d s 0x%x l 0x%x %dx%d bpp %d f 0x%x\n",
737 pView->screen.u32ViewIndex,
738 pView->screen.i32OriginX,
739 pView->screen.i32OriginY,
740 pView->screen.u32StartOffset,
741 pView->screen.u32LineSize,
742 pView->screen.u32Width,
743 pView->screen.u32Height,
744 pView->screen.u16BitsPerPixel,
745 pView->screen.u16Flags));
746
747 Log((" VBVA o 0x%x p %p\n",
748 pView->u32VBVAOffset,
749 pView->pVBVA));
750
751 Log((" PR cb 0x%x p %p\n",
752 pView->partialRecord.cb,
753 pView->partialRecord.pu8));
754 }
755
756 dumpMouseShapeInfo(&pCtx->mouseShapeInfo);
757}
758#endif /* DEBUG_sunlover */
759
760#define VBOXVBVASAVEDSTATE_VHWAAVAILABLE_MAGIC 0x12345678
761#define VBOXVBVASAVEDSTATE_VHWAUNAVAILABLE_MAGIC 0x9abcdef0
762
763#ifdef VBOX_WITH_VIDEOHWACCEL
764static void vbvaVHWAHHCommandReinit(VBOXVHWACMD* pHdr, VBOXVHWACMD_TYPE enmCmd, int32_t iDisplay)
765{
766 memset(pHdr, 0, VBOXVHWACMD_HEADSIZE());
767 pHdr->cRefs = 1;
768 pHdr->iDisplay = iDisplay;
769 pHdr->rc = VERR_NOT_IMPLEMENTED;
770 pHdr->enmCmd = enmCmd;
771 pHdr->Flags = VBOXVHWACMD_FLAG_HH_CMD;
772}
773
774static VBOXVHWACMD* vbvaVHWAHHCommandCreate (PVGASTATE pVGAState, VBOXVHWACMD_TYPE enmCmd, int32_t iDisplay, VBOXVHWACMD_LENGTH cbCmd)
775{
776 VBOXVHWACMD* pHdr = (VBOXVHWACMD*)RTMemAllocZ(cbCmd + VBOXVHWACMD_HEADSIZE());
777 Assert(pHdr);
778 if (pHdr)
779 vbvaVHWAHHCommandReinit(pHdr, enmCmd, iDisplay);
780
781 return pHdr;
782}
783
784DECLINLINE(void) vbvaVHWAHHCommandRelease (VBOXVHWACMD* pCmd)
785{
786 uint32_t cRefs = ASMAtomicDecU32(&pCmd->cRefs);
787 if(!cRefs)
788 {
789 RTMemFree(pCmd);
790 }
791}
792
793DECLINLINE(void) vbvaVHWAHHCommandRetain (VBOXVHWACMD* pCmd)
794{
795 ASMAtomicIncU32(&pCmd->cRefs);
796}
797
798static void vbvaVHWACommandComplete(PVGASTATE pVGAState, PVBOXVHWACMD pCommand, bool fAsyncCommand)
799{
800 if (fAsyncCommand)
801 {
802 Assert(pCommand->Flags & VBOXVHWACMD_FLAG_HG_ASYNCH);
803 vbvaVHWACommandCompleteAsynch(&pVGAState->IVBVACallbacks, pCommand);
804 }
805 else
806 {
807 Log(("VGA Command <<< Sync rc %d %#p, %d\n", pCommand->rc, pCommand, pCommand->enmCmd));
808 pCommand->Flags &= (~VBOXVHWACMD_FLAG_HG_ASYNCH);
809 }
810
811}
812
813static void vbvaVHWACommandCompleteAllPending(PVGASTATE pVGAState, int rc)
814{
815 if (!ASMAtomicUoReadU32(&pVGAState->pendingVhwaCommands.cPending))
816 return;
817
818 VBOX_VHWA_PENDINGCMD *pIter, *pNext;
819
820 PDMCritSectEnter(&pVGAState->CritSect, VERR_SEM_BUSY);
821
822 RTListForEachSafe(&pVGAState->pendingVhwaCommands.PendingList, pIter, pNext, VBOX_VHWA_PENDINGCMD, Node)
823 {
824 pIter->pCommand->rc = rc;
825 vbvaVHWACommandComplete(pVGAState, pIter->pCommand, true);
826
827 /* the command is submitted/processed, remove from the pend list */
828 RTListNodeRemove(&pIter->Node);
829 ASMAtomicDecU32(&pVGAState->pendingVhwaCommands.cPending);
830 RTMemFree(pIter);
831 }
832
833 PDMCritSectLeave(&pVGAState->CritSect);
834}
835
836static void vbvaVHWACommandClearAllPending(PVGASTATE pVGAState)
837{
838 if (!ASMAtomicUoReadU32(&pVGAState->pendingVhwaCommands.cPending))
839 return;
840
841 VBOX_VHWA_PENDINGCMD *pIter, *pNext;
842
843 PDMCritSectEnter(&pVGAState->CritSect, VERR_SEM_BUSY);
844
845 RTListForEachSafe(&pVGAState->pendingVhwaCommands.PendingList, pIter, pNext, VBOX_VHWA_PENDINGCMD, Node)
846 {
847 RTListNodeRemove(&pIter->Node);
848 ASMAtomicDecU32(&pVGAState->pendingVhwaCommands.cPending);
849 RTMemFree(pIter);
850 }
851
852 PDMCritSectLeave(&pVGAState->CritSect);
853}
854
855static void vbvaVHWACommandPend(PVGASTATE pVGAState, PVBOXVHWACMD pCommand)
856{
857 int rc = VERR_BUFFER_OVERFLOW;
858
859 if (ASMAtomicUoReadU32(&pVGAState->pendingVhwaCommands.cPending) < VBOX_VHWA_MAX_PENDING_COMMANDS)
860 {
861 VBOX_VHWA_PENDINGCMD *pPend = (VBOX_VHWA_PENDINGCMD*)RTMemAlloc(sizeof (*pPend));
862 if (pPend)
863 {
864 pCommand->Flags |= VBOXVHWACMD_FLAG_HG_ASYNCH;
865 pPend->pCommand = pCommand;
866 PDMCritSectEnter(&pVGAState->CritSect, VERR_SEM_BUSY);
867 if (ASMAtomicUoReadU32(&pVGAState->pendingVhwaCommands.cPending) < VBOX_VHWA_MAX_PENDING_COMMANDS)
868 {
869 RTListAppend(&pVGAState->pendingVhwaCommands.PendingList, &pPend->Node);
870 ASMAtomicIncU32(&pVGAState->pendingVhwaCommands.cPending);
871 PDMCritSectLeave(&pVGAState->CritSect);
872 return;
873 }
874 PDMCritSectLeave(&pVGAState->CritSect);
875 LogRel(("Pending command count has reached its threshold.. completing them all.."));
876 RTMemFree(pPend);
877 }
878 else
879 rc = VERR_NO_MEMORY;
880 }
881 else
882 LogRel(("Pending command count has reached its threshold, completing them all.."));
883
884 vbvaVHWACommandCompleteAllPending(pVGAState, rc);
885
886 pCommand->rc = rc;
887
888 vbvaVHWACommandComplete(pVGAState, pCommand, false);
889}
890
891static bool vbvaVHWACommandCanPend(PVBOXVHWACMD pCommand)
892{
893 switch (pCommand->enmCmd)
894 {
895 case VBOXVHWACMD_TYPE_HH_CONSTRUCT:
896 case VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEBEGIN:
897 case VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEEND:
898 case VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEPERFORM:
899 case VBOXVHWACMD_TYPE_HH_SAVESTATE_LOADPERFORM:
900 return false;
901 default:
902 return true;
903 }
904}
905
906static int vbvaVHWACommandSavePending(PVGASTATE pVGAState, PSSMHANDLE pSSM)
907{
908 int rc = SSMR3PutU32(pSSM, pVGAState->pendingVhwaCommands.cPending);
909 AssertRCReturn(rc, rc);
910 VBOX_VHWA_PENDINGCMD *pIter;
911 RTListForEach(&pVGAState->pendingVhwaCommands.PendingList, pIter, VBOX_VHWA_PENDINGCMD, Node)
912 {
913 rc = SSMR3PutU32(pSSM, (uint32_t)(((uint8_t*)pIter->pCommand) - ((uint8_t*)pVGAState->vram_ptrR3)));
914 AssertRCReturn(rc, rc);
915 }
916 return rc;
917}
918
919static int vbvaVHWACommandLoadPending(PVGASTATE pVGAState, PSSMHANDLE pSSM, uint32_t u32Version)
920{
921 if (u32Version < VGA_SAVEDSTATE_VERSION_WITH_PENDVHWA)
922 return VINF_SUCCESS;
923
924 int rc;
925 uint32_t u32;
926 rc = SSMR3GetU32(pSSM, &u32);
927 AssertRCReturn(rc, rc);
928 for (uint32_t i = 0; i < u32; ++i)
929 {
930 uint32_t off32;
931 rc = SSMR3GetU32(pSSM, &off32);
932 AssertRCReturn(rc, rc);
933 PVBOXVHWACMD pCommand = (PVBOXVHWACMD)(((uint8_t*)pVGAState->vram_ptrR3) + off32);
934 vbvaVHWACommandPend(pVGAState, pCommand);
935 }
936 return rc;
937}
938
939
940static bool vbvaVHWACommandSubmit(PVGASTATE pVGAState, PVBOXVHWACMD pCommand, bool fAsyncCommand)
941{
942 unsigned id = (unsigned)pCommand->iDisplay;
943 bool fPend = false;
944
945 if (pVGAState->pDrv->pfnVHWACommandProcess)
946 {
947 Log(("VGA Command >>> %#p, %d\n", pCommand, pCommand->enmCmd));
948 int rc = pVGAState->pDrv->pfnVHWACommandProcess(pVGAState->pDrv, pCommand);
949 if (rc == VINF_CALLBACK_RETURN)
950 {
951 Log(("VGA Command --- Going Async %#p, %d\n", pCommand, pCommand->enmCmd));
952 return true; /* command will be completed asynchronously, return right away */
953 }
954 else if (rc == VERR_INVALID_STATE)
955 {
956 Log(("VGA Command --- Trying Pend %#p, %d\n", pCommand, pCommand->enmCmd));
957 fPend = vbvaVHWACommandCanPend(pCommand);
958 if (!fPend)
959 {
960 Log(("VGA Command --- Can NOT Pend %#p, %d\n", pCommand, pCommand->enmCmd));
961 pCommand->rc = rc;
962 }
963 else
964 Log(("VGA Command --- Can Pend %#p, %d\n", pCommand, pCommand->enmCmd));
965 }
966 else
967 {
968 Log(("VGA Command --- Going Complete Sync rc %d %#p, %d\n", rc, pCommand, pCommand->enmCmd));
969 pCommand->rc = rc;
970 }
971
972 /* the command was completed, take a special care about it (seee below) */
973 }
974 else
975 {
976 AssertFailed();
977 pCommand->rc = VERR_INVALID_STATE;
978 }
979
980 if (fPend)
981 return false;
982
983 vbvaVHWACommandComplete(pVGAState, pCommand, fAsyncCommand);
984
985 return true;
986}
987
988static bool vbvaVHWACheckPendingCommands(PVGASTATE pVGAState)
989{
990 if (!ASMAtomicUoReadU32(&pVGAState->pendingVhwaCommands.cPending))
991 return true;
992
993 VBOX_VHWA_PENDINGCMD *pIter, *pNext;
994
995 PDMCritSectEnter(&pVGAState->CritSect, VERR_SEM_BUSY);
996
997 RTListForEachSafe(&pVGAState->pendingVhwaCommands.PendingList, pIter, pNext, VBOX_VHWA_PENDINGCMD, Node)
998 {
999 if (!vbvaVHWACommandSubmit(pVGAState, pIter->pCommand, true))
1000 {
1001 PDMCritSectLeave(&pVGAState->CritSect);
1002 return false; /* the command should be pended still */
1003 }
1004
1005 /* the command is submitted/processed, remove from the pend list */
1006 RTListNodeRemove(&pIter->Node);
1007 ASMAtomicDecU32(&pVGAState->pendingVhwaCommands.cPending);
1008 RTMemFree(pIter);
1009 }
1010
1011 PDMCritSectLeave(&pVGAState->CritSect);
1012
1013 return true;
1014}
1015
1016void vbvaTimerCb(PVGASTATE pVGAState)
1017{
1018 vbvaVHWACheckPendingCommands(pVGAState);
1019}
1020static void vbvaVHWAHandleCommand(PVGASTATE pVGAState, PVBOXVHWACMD pCmd)
1021{
1022 if (vbvaVHWACheckPendingCommands(pVGAState))
1023 {
1024 if (vbvaVHWACommandSubmit(pVGAState, pCmd, false))
1025 return;
1026 }
1027
1028 vbvaVHWACommandPend(pVGAState, pCmd);
1029}
1030
1031static DECLCALLBACK(void) vbvaVHWAHHCommandSetEventCallback(void * pContext)
1032{
1033 RTSemEventSignal((RTSEMEVENT)pContext);
1034}
1035
1036static int vbvaVHWAHHCommandPost(PVGASTATE pVGAState, VBOXVHWACMD* pCmd)
1037{
1038 RTSEMEVENT hComplEvent;
1039 int rc = RTSemEventCreate(&hComplEvent);
1040 AssertRC(rc);
1041 if(RT_SUCCESS(rc))
1042 {
1043 /* ensure the cmd is not deleted until we process it */
1044 vbvaVHWAHHCommandRetain (pCmd);
1045 VBOXVHWA_HH_CALLBACK_SET(pCmd, vbvaVHWAHHCommandSetEventCallback, (void*)hComplEvent);
1046 vbvaVHWAHandleCommand(pVGAState, pCmd);
1047 if((ASMAtomicReadU32((volatile uint32_t *)&pCmd->Flags) & VBOXVHWACMD_FLAG_HG_ASYNCH) != 0)
1048 {
1049 rc = RTSemEventWaitNoResume(hComplEvent, RT_INDEFINITE_WAIT);
1050 }
1051 else
1052 {
1053 /* the command is completed */
1054 }
1055
1056 AssertRC(rc);
1057 if(RT_SUCCESS(rc))
1058 {
1059 RTSemEventDestroy(hComplEvent);
1060 }
1061 vbvaVHWAHHCommandRelease(pCmd);
1062 }
1063 return rc;
1064}
1065
1066int vbvaVHWAConstruct (PVGASTATE pVGAState)
1067{
1068 pVGAState->pendingVhwaCommands.cPending = 0;
1069 RTListInit(&pVGAState->pendingVhwaCommands.PendingList);
1070
1071 VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(pVGAState, VBOXVHWACMD_TYPE_HH_CONSTRUCT, 0, sizeof(VBOXVHWACMD_HH_CONSTRUCT));
1072 Assert(pCmd);
1073 if(pCmd)
1074 {
1075 uint32_t iDisplay = 0;
1076 int rc = VINF_SUCCESS;
1077 VBOXVHWACMD_HH_CONSTRUCT * pBody = VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_HH_CONSTRUCT);
1078
1079 do
1080 {
1081 memset(pBody, 0, sizeof(VBOXVHWACMD_HH_CONSTRUCT));
1082
1083 PPDMDEVINS pDevIns = pVGAState->pDevInsR3;
1084 PVM pVM = PDMDevHlpGetVM(pDevIns);
1085
1086 pBody->pVM = pVM;
1087 pBody->pvVRAM = pVGAState->vram_ptrR3;
1088 pBody->cbVRAM = pVGAState->vram_size;
1089
1090 rc = vbvaVHWAHHCommandPost(pVGAState, pCmd);
1091 AssertRC(rc);
1092 if(RT_SUCCESS(rc))
1093 {
1094 rc = pCmd->rc;
1095 AssertMsg(RT_SUCCESS(rc) || rc == VERR_NOT_IMPLEMENTED, ("%Rrc\n", rc));
1096 if(rc == VERR_NOT_IMPLEMENTED)
1097 {
1098 /* @todo: set some flag in pVGAState indicating VHWA is not supported */
1099 /* VERR_NOT_IMPLEMENTED is not a failure, we just do not support it */
1100 rc = VINF_SUCCESS;
1101 }
1102
1103 if (!RT_SUCCESS(rc))
1104 break;
1105 }
1106 else
1107 break;
1108
1109 ++iDisplay;
1110 if (iDisplay >= pVGAState->cMonitors)
1111 break;
1112 vbvaVHWAHHCommandReinit(pCmd, VBOXVHWACMD_TYPE_HH_CONSTRUCT, (int32_t)iDisplay);
1113 } while (true);
1114
1115 vbvaVHWAHHCommandRelease(pCmd);
1116
1117 return rc;
1118 }
1119 return VERR_OUT_OF_RESOURCES;
1120}
1121
1122int vbvaVHWAReset (PVGASTATE pVGAState)
1123{
1124 vbvaVHWACommandClearAllPending(pVGAState);
1125
1126 /* ensure we have all pending cmds processed and h->g cmds disabled */
1127 VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(pVGAState, VBOXVHWACMD_TYPE_HH_RESET, 0, 0);
1128 Assert(pCmd);
1129 if(pCmd)
1130 {
1131 int rc = VINF_SUCCESS;
1132 uint32_t iDisplay = 0;
1133
1134 do
1135 {
1136 rc =vbvaVHWAHHCommandPost(pVGAState, pCmd);
1137 AssertRC(rc);
1138 if(RT_SUCCESS(rc))
1139 {
1140 rc = pCmd->rc;
1141 AssertMsg(RT_SUCCESS(rc) || rc == VERR_NOT_IMPLEMENTED, ("%Rrc\n", rc));
1142 if (rc == VERR_NOT_IMPLEMENTED)
1143 rc = VINF_SUCCESS;
1144 }
1145
1146 if (!RT_SUCCESS(rc))
1147 break;
1148
1149 ++iDisplay;
1150 if (iDisplay >= pVGAState->cMonitors)
1151 break;
1152 vbvaVHWAHHCommandReinit(pCmd, VBOXVHWACMD_TYPE_HH_RESET, (int32_t)iDisplay);
1153
1154 } while (true);
1155
1156 vbvaVHWAHHCommandRelease(pCmd);
1157
1158 return rc;
1159 }
1160 return VERR_OUT_OF_RESOURCES;
1161}
1162
1163typedef DECLCALLBACK(bool) FNVBOXVHWAHHCMDPRECB(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, void *pvContext);
1164typedef FNVBOXVHWAHHCMDPRECB *PFNVBOXVHWAHHCMDPRECB;
1165
1166typedef DECLCALLBACK(bool) FNVBOXVHWAHHCMDPOSTCB(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, int rc, void *pvContext);
1167typedef FNVBOXVHWAHHCMDPOSTCB *PFNVBOXVHWAHHCMDPOSTCB;
1168
1169int vbvaVHWAHHPost(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, PFNVBOXVHWAHHCMDPRECB pfnPre, PFNVBOXVHWAHHCMDPOSTCB pfnPost, void *pvContext)
1170{
1171 const VBOXVHWACMD_TYPE enmType = pCmd->enmCmd;
1172 int rc = VINF_SUCCESS;
1173 uint32_t iDisplay = 0;
1174
1175 do
1176 {
1177 if (!pfnPre || pfnPre(pVGAState, pCmd, iDisplay, pvContext))
1178 {
1179 rc = vbvaVHWAHHCommandPost(pVGAState, pCmd);
1180 AssertRC(rc);
1181 if (pfnPost)
1182 {
1183 if (!pfnPost(pVGAState, pCmd, iDisplay, rc, pvContext))
1184 {
1185 rc = VINF_SUCCESS;
1186 break;
1187 }
1188 rc = VINF_SUCCESS;
1189 }
1190 else if(RT_SUCCESS(rc))
1191 {
1192 rc = pCmd->rc;
1193 AssertMsg(RT_SUCCESS(rc) || rc == VERR_NOT_IMPLEMENTED, ("%Rrc\n", rc));
1194 if(rc == VERR_NOT_IMPLEMENTED)
1195 {
1196 rc = VINF_SUCCESS;
1197 }
1198 }
1199
1200 if (!RT_SUCCESS(rc))
1201 break;
1202 }
1203
1204 ++iDisplay;
1205 if (iDisplay >= pVGAState->cMonitors)
1206 break;
1207 vbvaVHWAHHCommandReinit(pCmd, enmType, (int32_t)iDisplay);
1208 } while (true);
1209
1210 return rc;
1211}
1212
1213/* @todo call this also on reset? */
1214int vbvaVHWAEnable (PVGASTATE pVGAState, bool bEnable)
1215{
1216 const VBOXVHWACMD_TYPE enmType = bEnable ? VBOXVHWACMD_TYPE_HH_ENABLE : VBOXVHWACMD_TYPE_HH_DISABLE;
1217 VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(pVGAState,
1218 enmType,
1219 0, 0);
1220 Assert(pCmd);
1221 if(pCmd)
1222 {
1223 int rc = vbvaVHWAHHPost (pVGAState, pCmd, NULL, NULL, NULL);
1224 vbvaVHWAHHCommandRelease(pCmd);
1225 return rc;
1226 }
1227 return VERR_OUT_OF_RESOURCES;
1228}
1229
1230int vboxVBVASaveStatePrep (PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1231{
1232 /* ensure we have no pending commands */
1233 return vbvaVHWAEnable(PDMINS_2_DATA(pDevIns, PVGASTATE), false);
1234}
1235
1236int vboxVBVASaveStateDone (PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1237{
1238 /* ensure we have no pending commands */
1239 return vbvaVHWAEnable(PDMINS_2_DATA(pDevIns, PVGASTATE), true);
1240}
1241
1242int vbvaVHWACommandCompleteAsynch(PPDMIDISPLAYVBVACALLBACKS pInterface, PVBOXVHWACMD pCmd)
1243{
1244 int rc;
1245 Log(("VGA Command <<< Async rc %d %#p, %d\n", pCmd->rc, pCmd, pCmd->enmCmd));
1246
1247 if((pCmd->Flags & VBOXVHWACMD_FLAG_HH_CMD) == 0)
1248 {
1249 PVGASTATE pVGAState = PPDMIDISPLAYVBVACALLBACKS_2_PVGASTATE(pInterface);
1250 PHGSMIINSTANCE pIns = pVGAState->pHGSMI;
1251
1252 Assert(pCmd->Flags & VBOXVHWACMD_FLAG_HG_ASYNCH);
1253#ifdef VBOX_WITH_WDDM
1254 if (pVGAState->fGuestCaps & VBVACAPS_COMPLETEGCMD_BY_IOREAD)
1255 {
1256 rc = HGSMICompleteGuestCommand(pIns, pCmd, !!(pCmd->Flags & VBOXVHWACMD_FLAG_GH_ASYNCH_IRQ));
1257 AssertRC(rc);
1258 }
1259 else
1260#endif
1261 {
1262 VBVAHOSTCMD *pHostCmd;
1263 int32_t iDisplay = pCmd->iDisplay;
1264
1265 if(pCmd->Flags & VBOXVHWACMD_FLAG_GH_ASYNCH_EVENT)
1266 {
1267 rc = HGSMIHostCommandAlloc (pIns,
1268 (void**)&pHostCmd,
1269 VBVAHOSTCMD_SIZE(sizeof(VBVAHOSTCMDEVENT)),
1270 HGSMI_CH_VBVA,
1271 VBVAHG_EVENT);
1272 AssertRC(rc);
1273 if(RT_SUCCESS(rc))
1274 {
1275 memset(pHostCmd, 0 , VBVAHOSTCMD_SIZE(sizeof(VBVAHOSTCMDEVENT)));
1276 pHostCmd->iDstID = pCmd->iDisplay;
1277 pHostCmd->customOpCode = 0;
1278 VBVAHOSTCMDEVENT *pBody = VBVAHOSTCMD_BODY(pHostCmd, VBVAHOSTCMDEVENT);
1279 pBody->pEvent = pCmd->GuestVBVAReserved1;
1280 }
1281 }
1282 else
1283 {
1284 HGSMIOFFSET offCmd = HGSMIPointerToOffsetHost (pIns, pCmd);
1285 Assert(offCmd != HGSMIOFFSET_VOID);
1286 if(offCmd != HGSMIOFFSET_VOID)
1287 {
1288 rc = HGSMIHostCommandAlloc (pIns,
1289 (void**)&pHostCmd,
1290 VBVAHOSTCMD_SIZE(sizeof(VBVAHOSTCMDVHWACMDCOMPLETE)),
1291 HGSMI_CH_VBVA,
1292 VBVAHG_DISPLAY_CUSTOM);
1293 AssertRC(rc);
1294 if(RT_SUCCESS(rc))
1295 {
1296 memset(pHostCmd, 0 , VBVAHOSTCMD_SIZE(sizeof(VBVAHOSTCMDVHWACMDCOMPLETE)));
1297 pHostCmd->iDstID = pCmd->iDisplay;
1298 pHostCmd->customOpCode = VBVAHG_DCUSTOM_VHWA_CMDCOMPLETE;
1299 VBVAHOSTCMDVHWACMDCOMPLETE *pBody = VBVAHOSTCMD_BODY(pHostCmd, VBVAHOSTCMDVHWACMDCOMPLETE);
1300 pBody->offCmd = offCmd;
1301 }
1302 }
1303 else
1304 {
1305 rc = VERR_INVALID_PARAMETER;
1306 }
1307 }
1308
1309 if(RT_SUCCESS(rc))
1310 {
1311 rc = HGSMIHostCommandProcessAndFreeAsynch(pIns, pHostCmd, (pCmd->Flags & VBOXVHWACMD_FLAG_GH_ASYNCH_IRQ) != 0);
1312 AssertRC(rc);
1313 if(RT_SUCCESS(rc))
1314 {
1315 return rc;
1316 }
1317 HGSMIHostCommandFree (pIns, pHostCmd);
1318 }
1319 }
1320 }
1321 else
1322 {
1323 PFNVBOXVHWA_HH_CALLBACK pfn = VBOXVHWA_HH_CALLBACK_GET(pCmd);
1324 if(pfn)
1325 {
1326 pfn(VBOXVHWA_HH_CALLBACK_GET_ARG(pCmd));
1327 }
1328 rc = VINF_SUCCESS;
1329 }
1330 return rc;
1331}
1332
1333typedef struct VBOXVBVASAVEDSTATECBDATA
1334{
1335 PSSMHANDLE pSSM;
1336 int rc;
1337 bool ab2DOn[VBOX_VIDEO_MAX_SCREENS];
1338} VBOXVBVASAVEDSTATECBDATA, *PVBOXVBVASAVEDSTATECBDATA;
1339
1340static DECLCALLBACK(bool) vboxVBVASaveStateBeginPostCb(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, int rc, void *pvContext)
1341{
1342 PVBOXVBVASAVEDSTATECBDATA pData = (PVBOXVBVASAVEDSTATECBDATA)pvContext;
1343 if (RT_FAILURE(pData->rc))
1344 return false;
1345 if (RT_FAILURE(rc))
1346 {
1347 pData->rc = rc;
1348 return false;
1349 }
1350
1351 Assert(iDisplay < RT_ELEMENTS(pData->ab2DOn));
1352 if (iDisplay >= RT_ELEMENTS(pData->ab2DOn))
1353 {
1354 pData->rc = VERR_INVALID_PARAMETER;
1355 return false;
1356 }
1357
1358 Assert(RT_SUCCESS(pCmd->rc) || pCmd->rc == VERR_NOT_IMPLEMENTED);
1359 if (RT_SUCCESS(pCmd->rc))
1360 {
1361 pData->ab2DOn[iDisplay] = true;
1362 }
1363 else if (pCmd->rc != VERR_NOT_IMPLEMENTED)
1364 {
1365 pData->rc = pCmd->rc;
1366 return false;
1367 }
1368
1369 return true;
1370}
1371
1372static DECLCALLBACK(bool) vboxVBVASaveStatePerformPreCb(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, void *pvContext)
1373{
1374 PVBOXVBVASAVEDSTATECBDATA pData = (PVBOXVBVASAVEDSTATECBDATA)pvContext;
1375 if (RT_FAILURE(pData->rc))
1376 return false;
1377
1378 Assert(iDisplay < RT_ELEMENTS(pData->ab2DOn));
1379 if (iDisplay >= RT_ELEMENTS(pData->ab2DOn))
1380 {
1381 pData->rc = VERR_INVALID_PARAMETER;
1382 return false;
1383 }
1384
1385 int rc;
1386
1387 if (pData->ab2DOn[iDisplay])
1388 {
1389 rc = SSMR3PutU32 (pData->pSSM, VBOXVBVASAVEDSTATE_VHWAAVAILABLE_MAGIC); AssertRC(rc);
1390 if (RT_FAILURE(rc))
1391 {
1392 pData->rc = rc;
1393 return false;
1394 }
1395 return true;
1396 }
1397
1398 rc = SSMR3PutU32 (pData->pSSM, VBOXVBVASAVEDSTATE_VHWAUNAVAILABLE_MAGIC); AssertRC(rc);
1399 if (RT_FAILURE(rc))
1400 {
1401 pData->rc = rc;
1402 return false;
1403 }
1404
1405 return false;
1406}
1407
1408static DECLCALLBACK(bool) vboxVBVASaveStateEndPreCb(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, void *pvContext)
1409{
1410 PVBOXVBVASAVEDSTATECBDATA pData = (PVBOXVBVASAVEDSTATECBDATA)pvContext;
1411 Assert(iDisplay < RT_ELEMENTS(pData->ab2DOn));
1412 if (pData->ab2DOn[iDisplay])
1413 {
1414 return true;
1415 }
1416
1417 return false;
1418}
1419
1420static DECLCALLBACK(bool) vboxVBVALoadStatePerformPostCb(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, int rc, void *pvContext)
1421{
1422 PVBOXVBVASAVEDSTATECBDATA pData = (PVBOXVBVASAVEDSTATECBDATA)pvContext;
1423 if (RT_FAILURE(pData->rc))
1424 return false;
1425 if (RT_FAILURE(rc))
1426 {
1427 pData->rc = rc;
1428 return false;
1429 }
1430
1431 Assert(iDisplay < RT_ELEMENTS(pData->ab2DOn));
1432 if (iDisplay >= RT_ELEMENTS(pData->ab2DOn))
1433 {
1434 pData->rc = VERR_INVALID_PARAMETER;
1435 return false;
1436 }
1437
1438 Assert(RT_SUCCESS(pCmd->rc) || pCmd->rc == VERR_NOT_IMPLEMENTED);
1439 if (pCmd->rc == VERR_NOT_IMPLEMENTED)
1440 {
1441 pData->rc = SSMR3SkipToEndOfUnit(pData->pSSM);
1442 AssertRC(pData->rc);
1443 return false;
1444 }
1445 if (RT_FAILURE(pCmd->rc))
1446 {
1447 pData->rc = pCmd->rc;
1448 return false;
1449 }
1450
1451 return true;
1452}
1453
1454static DECLCALLBACK(bool) vboxVBVALoadStatePerformPreCb(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, void *pvContext)
1455{
1456 PVBOXVBVASAVEDSTATECBDATA pData = (PVBOXVBVASAVEDSTATECBDATA)pvContext;
1457 if (RT_FAILURE(pData->rc))
1458 return false;
1459
1460 Assert(iDisplay < RT_ELEMENTS(pData->ab2DOn));
1461 if (iDisplay >= RT_ELEMENTS(pData->ab2DOn))
1462 {
1463 pData->rc = VERR_INVALID_PARAMETER;
1464 return false;
1465 }
1466
1467 int rc;
1468 uint32_t u32;
1469 rc = SSMR3GetU32(pData->pSSM, &u32); AssertRC(rc);
1470 if (RT_FAILURE(rc))
1471 {
1472 pData->rc = rc;
1473 return false;
1474 }
1475
1476 switch (u32)
1477 {
1478 case VBOXVBVASAVEDSTATE_VHWAAVAILABLE_MAGIC:
1479 return true;
1480 case VBOXVBVASAVEDSTATE_VHWAUNAVAILABLE_MAGIC:
1481 return false;
1482 default:
1483 pData->rc = VERR_INVALID_STATE;
1484 return false;
1485 }
1486}
1487#endif /* #ifdef VBOX_WITH_VIDEOHWACCEL */
1488
1489int vboxVBVASaveDevStateExec (PVGASTATE pVGAState, PSSMHANDLE pSSM)
1490{
1491 PHGSMIINSTANCE pIns = pVGAState->pHGSMI;
1492 int rc = HGSMIHostSaveStateExec (pIns, pSSM);
1493 if (RT_SUCCESS(rc))
1494 {
1495 /* Save VBVACONTEXT. */
1496 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pIns);
1497
1498 if (!pCtx)
1499 {
1500 AssertFailed();
1501
1502 /* Still write a valid value to the SSM. */
1503 rc = SSMR3PutU32 (pSSM, 0);
1504 AssertRCReturn(rc, rc);
1505 }
1506 else
1507 {
1508#ifdef DEBUG_sunlover
1509 dumpctx(pCtx);
1510#endif
1511
1512 rc = SSMR3PutU32 (pSSM, pCtx->cViews);
1513 AssertRCReturn(rc, rc);
1514
1515 uint32_t iView;
1516 for (iView = 0; iView < pCtx->cViews; iView++)
1517 {
1518 VBVAVIEW *pView = &pCtx->aViews[iView];
1519
1520 rc = SSMR3PutU32 (pSSM, pView->view.u32ViewIndex);
1521 AssertRCReturn(rc, rc);
1522 rc = SSMR3PutU32 (pSSM, pView->view.u32ViewOffset);
1523 AssertRCReturn(rc, rc);
1524 rc = SSMR3PutU32 (pSSM, pView->view.u32ViewSize);
1525 AssertRCReturn(rc, rc);
1526 rc = SSMR3PutU32 (pSSM, pView->view.u32MaxScreenSize);
1527 AssertRCReturn(rc, rc);
1528
1529 rc = SSMR3PutU32 (pSSM, pView->screen.u32ViewIndex);
1530 AssertRCReturn(rc, rc);
1531 rc = SSMR3PutS32 (pSSM, pView->screen.i32OriginX);
1532 AssertRCReturn(rc, rc);
1533 rc = SSMR3PutS32 (pSSM, pView->screen.i32OriginY);
1534 AssertRCReturn(rc, rc);
1535 rc = SSMR3PutU32 (pSSM, pView->screen.u32StartOffset);
1536 AssertRCReturn(rc, rc);
1537 rc = SSMR3PutU32 (pSSM, pView->screen.u32LineSize);
1538 AssertRCReturn(rc, rc);
1539 rc = SSMR3PutU32 (pSSM, pView->screen.u32Width);
1540 AssertRCReturn(rc, rc);
1541 rc = SSMR3PutU32 (pSSM, pView->screen.u32Height);
1542 AssertRCReturn(rc, rc);
1543 rc = SSMR3PutU16 (pSSM, pView->screen.u16BitsPerPixel);
1544 AssertRCReturn(rc, rc);
1545 rc = SSMR3PutU16 (pSSM, pView->screen.u16Flags);
1546 AssertRCReturn(rc, rc);
1547
1548 rc = SSMR3PutU32 (pSSM, pView->pVBVA? pView->u32VBVAOffset: HGSMIOFFSET_VOID);
1549 AssertRCReturn(rc, rc);
1550
1551 rc = SSMR3PutU32 (pSSM, pView->partialRecord.cb);
1552 AssertRCReturn(rc, rc);
1553
1554 if (pView->partialRecord.cb > 0)
1555 {
1556 rc = SSMR3PutMem (pSSM, pView->partialRecord.pu8, pView->partialRecord.cb);
1557 AssertRCReturn(rc, rc);
1558 }
1559 }
1560
1561 /* Save mouse pointer shape information. */
1562 rc = SSMR3PutBool (pSSM, pCtx->mouseShapeInfo.fSet);
1563 AssertRCReturn(rc, rc);
1564 rc = SSMR3PutBool (pSSM, pCtx->mouseShapeInfo.fVisible);
1565 AssertRCReturn(rc, rc);
1566 rc = SSMR3PutBool (pSSM, pCtx->mouseShapeInfo.fAlpha);
1567 AssertRCReturn(rc, rc);
1568 rc = SSMR3PutU32 (pSSM, pCtx->mouseShapeInfo.u32HotX);
1569 AssertRCReturn(rc, rc);
1570 rc = SSMR3PutU32 (pSSM, pCtx->mouseShapeInfo.u32HotY);
1571 AssertRCReturn(rc, rc);
1572 rc = SSMR3PutU32 (pSSM, pCtx->mouseShapeInfo.u32Width);
1573 AssertRCReturn(rc, rc);
1574 rc = SSMR3PutU32 (pSSM, pCtx->mouseShapeInfo.u32Height);
1575 AssertRCReturn(rc, rc);
1576 rc = SSMR3PutU32 (pSSM, pCtx->mouseShapeInfo.cbShape);
1577 AssertRCReturn(rc, rc);
1578 if (pCtx->mouseShapeInfo.cbShape)
1579 {
1580 rc = SSMR3PutMem (pSSM, pCtx->mouseShapeInfo.pu8Shape, pCtx->mouseShapeInfo.cbShape);
1581 AssertRCReturn(rc, rc);
1582 }
1583
1584#ifdef VBOX_WITH_WDDM
1585 /* Size of some additional data. For future extensions. */
1586 rc = SSMR3PutU32 (pSSM, 4);
1587 AssertRCReturn(rc, rc);
1588 rc = SSMR3PutU32 (pSSM, pVGAState->fGuestCaps);
1589 AssertRCReturn(rc, rc);
1590#else
1591 /* Size of some additional data. For future extensions. */
1592 rc = SSMR3PutU32 (pSSM, 0);
1593 AssertRCReturn(rc, rc);
1594#endif
1595 }
1596 }
1597
1598 return rc;
1599}
1600
1601int vboxVBVASaveStateExec (PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1602{
1603 PVGASTATE pVGAState = PDMINS_2_DATA(pDevIns, PVGASTATE);
1604 int rc;
1605#ifdef VBOX_WITH_VIDEOHWACCEL
1606 VBOXVBVASAVEDSTATECBDATA VhwaData = {0};
1607 VhwaData.pSSM = pSSM;
1608 uint32_t cbCmd = sizeof (VBOXVHWACMD_HH_SAVESTATE_SAVEPERFORM); /* maximum cmd size */
1609 VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(pVGAState, VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEBEGIN, 0, cbCmd);
1610 Assert(pCmd);
1611 if(pCmd)
1612 {
1613 vbvaVHWAHHPost (pVGAState, pCmd, NULL, vboxVBVASaveStateBeginPostCb, &VhwaData);
1614 rc = VhwaData.rc;
1615 AssertRC(rc);
1616 if (RT_SUCCESS(rc))
1617 {
1618#endif
1619 rc = vboxVBVASaveDevStateExec (pVGAState, pSSM);
1620 AssertRC(rc);
1621#ifdef VBOX_WITH_VIDEOHWACCEL
1622 if (RT_SUCCESS(rc))
1623 {
1624 vbvaVHWAHHCommandReinit(pCmd, VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEPERFORM, 0);
1625 VBOXVHWACMD_HH_SAVESTATE_SAVEPERFORM *pSave = VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_HH_SAVESTATE_SAVEPERFORM);
1626 pSave->pSSM = pSSM;
1627 vbvaVHWAHHPost (pVGAState, pCmd, vboxVBVASaveStatePerformPreCb, NULL, &VhwaData);
1628 rc = VhwaData.rc;
1629 AssertRC(rc);
1630 if (RT_SUCCESS(rc))
1631 {
1632 rc = vbvaVHWACommandSavePending(pVGAState, pSSM);
1633 AssertRCReturn(rc, rc);
1634
1635 vbvaVHWAHHCommandReinit(pCmd, VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEEND, 0);
1636 vbvaVHWAHHPost (pVGAState, pCmd, vboxVBVASaveStateEndPreCb, NULL, &VhwaData);
1637 rc = VhwaData.rc;
1638 AssertRC(rc);
1639 }
1640 }
1641 }
1642
1643 vbvaVHWAHHCommandRelease(pCmd);
1644 }
1645 else
1646 rc = VERR_OUT_OF_RESOURCES;
1647#else
1648 if (RT_SUCCESS(rc))
1649 {
1650 for (uint32_t i = 0; i < pVGAState->cMonitors; ++i)
1651 {
1652 rc = SSMR3PutU32 (pSSM, VBOXVBVASAVEDSTATE_VHWAUNAVAILABLE_MAGIC);
1653 AssertRCReturn(rc, rc);
1654 }
1655 }
1656#endif
1657 return rc;
1658}
1659
1660int vboxVBVALoadStateExec (PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t u32Version)
1661{
1662 if (u32Version < VGA_SAVEDSTATE_VERSION_HGSMI)
1663 {
1664 /* Nothing was saved. */
1665 return VINF_SUCCESS;
1666 }
1667
1668 PVGASTATE pVGAState = PDMINS_2_DATA(pDevIns, PVGASTATE);
1669 PHGSMIINSTANCE pIns = pVGAState->pHGSMI;
1670 int rc = HGSMIHostLoadStateExec (pIns, pSSM, u32Version);
1671 if (RT_SUCCESS(rc))
1672 {
1673 /* Load VBVACONTEXT. */
1674 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pIns);
1675
1676 if (!pCtx)
1677 {
1678 /* This should not happen. */
1679 AssertFailed();
1680 rc = VERR_INVALID_PARAMETER;
1681 }
1682 else
1683 {
1684 uint32_t cViews = 0;
1685 rc = SSMR3GetU32 (pSSM, &cViews);
1686 AssertRCReturn(rc, rc);
1687
1688 uint32_t iView;
1689 for (iView = 0; iView < cViews; iView++)
1690 {
1691 VBVAVIEW *pView = &pCtx->aViews[iView];
1692
1693 rc = SSMR3GetU32 (pSSM, &pView->view.u32ViewIndex);
1694 AssertRCReturn(rc, rc);
1695 rc = SSMR3GetU32 (pSSM, &pView->view.u32ViewOffset);
1696 AssertRCReturn(rc, rc);
1697 rc = SSMR3GetU32 (pSSM, &pView->view.u32ViewSize);
1698 AssertRCReturn(rc, rc);
1699 rc = SSMR3GetU32 (pSSM, &pView->view.u32MaxScreenSize);
1700 AssertRCReturn(rc, rc);
1701
1702 rc = SSMR3GetU32 (pSSM, &pView->screen.u32ViewIndex);
1703 AssertRCReturn(rc, rc);
1704 rc = SSMR3GetS32 (pSSM, &pView->screen.i32OriginX);
1705 AssertRCReturn(rc, rc);
1706 rc = SSMR3GetS32 (pSSM, &pView->screen.i32OriginY);
1707 AssertRCReturn(rc, rc);
1708 rc = SSMR3GetU32 (pSSM, &pView->screen.u32StartOffset);
1709 AssertRCReturn(rc, rc);
1710 rc = SSMR3GetU32 (pSSM, &pView->screen.u32LineSize);
1711 AssertRCReturn(rc, rc);
1712 rc = SSMR3GetU32 (pSSM, &pView->screen.u32Width);
1713 AssertRCReturn(rc, rc);
1714 rc = SSMR3GetU32 (pSSM, &pView->screen.u32Height);
1715 AssertRCReturn(rc, rc);
1716 rc = SSMR3GetU16 (pSSM, &pView->screen.u16BitsPerPixel);
1717 AssertRCReturn(rc, rc);
1718 rc = SSMR3GetU16 (pSSM, &pView->screen.u16Flags);
1719 AssertRCReturn(rc, rc);
1720
1721 rc = SSMR3GetU32 (pSSM, &pView->u32VBVAOffset);
1722 AssertRCReturn(rc, rc);
1723
1724 rc = SSMR3GetU32 (pSSM, &pView->partialRecord.cb);
1725 AssertRCReturn(rc, rc);
1726
1727 if (pView->partialRecord.cb == 0)
1728 {
1729 pView->partialRecord.pu8 = NULL;
1730 }
1731 else
1732 {
1733 Assert(pView->partialRecord.pu8 == NULL); /* Should be it. */
1734
1735 uint8_t *pu8 = (uint8_t *)RTMemAlloc (pView->partialRecord.cb);
1736
1737 if (!pu8)
1738 {
1739 return VERR_NO_MEMORY;
1740 }
1741
1742 pView->partialRecord.pu8 = pu8;
1743
1744 rc = SSMR3GetMem (pSSM, pView->partialRecord.pu8, pView->partialRecord.cb);
1745 AssertRCReturn(rc, rc);
1746 }
1747
1748 if (pView->u32VBVAOffset == HGSMIOFFSET_VOID)
1749 {
1750 pView->pVBVA = NULL;
1751 }
1752 else
1753 {
1754 pView->pVBVA = (VBVABUFFER *)HGSMIOffsetToPointerHost (pIns, pView->u32VBVAOffset);
1755 }
1756 }
1757
1758 if (u32Version > VGA_SAVEDSTATE_VERSION_WITH_CONFIG)
1759 {
1760 /* Read mouse pointer shape information. */
1761 rc = SSMR3GetBool (pSSM, &pCtx->mouseShapeInfo.fSet);
1762 AssertRCReturn(rc, rc);
1763 rc = SSMR3GetBool (pSSM, &pCtx->mouseShapeInfo.fVisible);
1764 AssertRCReturn(rc, rc);
1765 rc = SSMR3GetBool (pSSM, &pCtx->mouseShapeInfo.fAlpha);
1766 AssertRCReturn(rc, rc);
1767 rc = SSMR3GetU32 (pSSM, &pCtx->mouseShapeInfo.u32HotX);
1768 AssertRCReturn(rc, rc);
1769 rc = SSMR3GetU32 (pSSM, &pCtx->mouseShapeInfo.u32HotY);
1770 AssertRCReturn(rc, rc);
1771 rc = SSMR3GetU32 (pSSM, &pCtx->mouseShapeInfo.u32Width);
1772 AssertRCReturn(rc, rc);
1773 rc = SSMR3GetU32 (pSSM, &pCtx->mouseShapeInfo.u32Height);
1774 AssertRCReturn(rc, rc);
1775 rc = SSMR3GetU32 (pSSM, &pCtx->mouseShapeInfo.cbShape);
1776 AssertRCReturn(rc, rc);
1777 if (pCtx->mouseShapeInfo.cbShape)
1778 {
1779 pCtx->mouseShapeInfo.pu8Shape = (uint8_t *)RTMemAlloc(pCtx->mouseShapeInfo.cbShape);
1780 if (pCtx->mouseShapeInfo.pu8Shape == NULL)
1781 {
1782 return VERR_NO_MEMORY;
1783 }
1784 pCtx->mouseShapeInfo.cbAllocated = pCtx->mouseShapeInfo.cbShape;
1785 rc = SSMR3GetMem (pSSM, pCtx->mouseShapeInfo.pu8Shape, pCtx->mouseShapeInfo.cbShape);
1786 AssertRCReturn(rc, rc);
1787 }
1788 else
1789 {
1790 pCtx->mouseShapeInfo.pu8Shape = NULL;
1791 }
1792
1793 /* Size of some additional data. For future extensions. */
1794 uint32_t cbExtra = 0;
1795 rc = SSMR3GetU32 (pSSM, &cbExtra);
1796 AssertRCReturn(rc, rc);
1797#ifdef VBOX_WITH_WDDM
1798 if (cbExtra >= 4)
1799 {
1800 rc = SSMR3GetU32 (pSSM, &pVGAState->fGuestCaps);
1801 AssertRCReturn(rc, rc);
1802 cbExtra -= 4;
1803 }
1804#endif
1805 if (cbExtra > 0)
1806 {
1807 rc = SSMR3Skip(pSSM, cbExtra);
1808 AssertRCReturn(rc, rc);
1809 }
1810 }
1811
1812 pCtx->cViews = iView;
1813 LogFlowFunc(("%d views loaded\n", pCtx->cViews));
1814
1815 if (u32Version > VGA_SAVEDSTATE_VERSION_WDDM)
1816 {
1817#ifdef VBOX_WITH_VIDEOHWACCEL
1818 uint32_t cbCmd = sizeof (VBOXVHWACMD_HH_SAVESTATE_LOADPERFORM); /* maximum cmd size */
1819 VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(pVGAState, VBOXVHWACMD_TYPE_HH_SAVESTATE_LOADPERFORM, 0, cbCmd);
1820 Assert(pCmd);
1821 if(pCmd)
1822 {
1823 VBOXVBVASAVEDSTATECBDATA VhwaData = {0};
1824 VhwaData.pSSM = pSSM;
1825 VBOXVHWACMD_HH_SAVESTATE_LOADPERFORM *pLoad = VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_HH_SAVESTATE_LOADPERFORM);
1826 pLoad->pSSM = pSSM;
1827 vbvaVHWAHHPost (pVGAState, pCmd, vboxVBVALoadStatePerformPreCb, vboxVBVALoadStatePerformPostCb, &VhwaData);
1828 rc = VhwaData.rc;
1829 vbvaVHWAHHCommandRelease(pCmd);
1830 AssertRCReturn(rc, rc);
1831
1832 rc = vbvaVHWACommandLoadPending(pVGAState, pSSM, u32Version);
1833 AssertRCReturn(rc, rc);
1834 }
1835 else
1836 {
1837 rc = VERR_OUT_OF_RESOURCES;
1838 }
1839#else
1840 rc = SSMR3SkipToEndOfUnit(pSSM);
1841 AssertRCReturn(rc, rc);
1842#endif
1843 }
1844
1845#ifdef DEBUG_sunlover
1846 dumpctx(pCtx);
1847#endif
1848 }
1849 }
1850
1851 return rc;
1852}
1853
1854int vboxVBVALoadStateDone (PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1855{
1856 PVGASTATE pVGAState = PDMINS_2_DATA(pDevIns, PVGASTATE);
1857 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pVGAState->pHGSMI);
1858
1859 if (pCtx)
1860 {
1861 uint32_t iView;
1862 for (iView = 0; iView < pCtx->cViews; iView++)
1863 {
1864 VBVAVIEW *pView = &pCtx->aViews[iView];
1865
1866 if (pView->pVBVA)
1867 {
1868 vbvaEnable (iView, pVGAState, pCtx, pView->pVBVA, pView->u32VBVAOffset, true /* fRestored */);
1869 vbvaResize (pVGAState, pView, &pView->screen);
1870 }
1871 }
1872
1873 if (pCtx->mouseShapeInfo.fSet)
1874 {
1875 vbvaUpdateMousePointerShape(pVGAState, &pCtx->mouseShapeInfo, true, pCtx->mouseShapeInfo.pu8Shape);
1876 }
1877 }
1878
1879 return VINF_SUCCESS;
1880}
1881
1882void VBVARaiseIrq (PVGASTATE pVGAState, uint32_t fFlags)
1883{
1884 PPDMDEVINS pDevIns = pVGAState->pDevInsR3;
1885 PDMCritSectEnter(&pVGAState->CritSect, VERR_SEM_BUSY);
1886
1887 HGSMISetHostGuestFlags(pVGAState->pHGSMI, HGSMIHOSTFLAGS_IRQ | fFlags);
1888 PDMDevHlpPCISetIrq(pDevIns, 0, PDM_IRQ_LEVEL_HIGH);
1889
1890 PDMCritSectLeave(&pVGAState->CritSect);
1891}
1892
1893void VBVARaiseIrqNoWait(PVGASTATE pVGAState, uint32_t fFlags)
1894{
1895 PPDMDEVINS pDevIns = pVGAState->pDevInsR3;
1896 PDMCritSectEnter(&pVGAState->CritSect, VERR_SEM_BUSY);
1897
1898 HGSMISetHostGuestFlags(pVGAState->pHGSMI, HGSMIHOSTFLAGS_IRQ | fFlags);
1899 PDMDevHlpPCISetIrqNoWait(pDevIns, 0, PDM_IRQ_LEVEL_HIGH);
1900
1901 PDMCritSectLeave(&pVGAState->CritSect);
1902}
1903
1904
1905/*
1906 *
1907 * New VBVA uses a new interface id: #define VBE_DISPI_ID_VBOX_VIDEO 0xBE01
1908 *
1909 * VBVA uses two 32 bits IO ports to write VRAM offsets of shared memory blocks for commands.
1910 * Read Write
1911 * Host port 0x3b0 to process completed
1912 * Guest port 0x3d0 control value? to process
1913 *
1914 */
1915
1916static DECLCALLBACK(void) vbvaNotifyGuest (void *pvCallback)
1917{
1918#if defined(VBOX_WITH_HGSMI) && (defined(VBOX_WITH_VIDEOHWACCEL) || defined(VBOX_WITH_VDMA) || defined(VBOX_WITH_WDDM))
1919 PVGASTATE pVGAState = (PVGASTATE)pvCallback;
1920 VBVARaiseIrq (pVGAState, 0);
1921#else
1922 NOREF(pvCallback);
1923 /* Do nothing. Later the VMMDev/VGA IRQ can be used for the notification. */
1924#endif
1925}
1926
1927/* The guest submitted a buffer. @todo Verify all guest data. */
1928static DECLCALLBACK(int) vbvaChannelHandler (void *pvHandler, uint16_t u16ChannelInfo, void *pvBuffer, HGSMISIZE cbBuffer)
1929{
1930 int rc = VINF_SUCCESS;
1931
1932 LogFlowFunc(("pvHandler %p, u16ChannelInfo %d, pvBuffer %p, cbBuffer %u\n",
1933 pvHandler, u16ChannelInfo, pvBuffer, cbBuffer));
1934
1935 PVGASTATE pVGAState = (PVGASTATE)pvHandler;
1936 PHGSMIINSTANCE pIns = pVGAState->pHGSMI;
1937 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pIns);
1938
1939 switch (u16ChannelInfo)
1940 {
1941#ifdef VBOX_WITH_VDMA
1942 case VBVA_VDMA_CMD:
1943 {
1944 if (cbBuffer < VBoxSHGSMIBufferHeaderSize() + sizeof (VBOXVDMACBUF_DR))
1945 {
1946 rc = VERR_INVALID_PARAMETER;
1947 break;
1948 }
1949 PVBOXVDMACBUF_DR pCmd = (PVBOXVDMACBUF_DR)VBoxSHGSMIBufferData ((PVBOXSHGSMIHEADER)pvBuffer);
1950 vboxVDMACommand(pVGAState->pVdma, pCmd, cbBuffer - VBoxSHGSMIBufferHeaderSize());
1951 rc = VINF_SUCCESS;
1952 break;
1953 }
1954 case VBVA_VDMA_CTL:
1955 {
1956 if (cbBuffer < VBoxSHGSMIBufferHeaderSize() + sizeof (VBOXVDMA_CTL))
1957 {
1958 rc = VERR_INVALID_PARAMETER;
1959 break;
1960 }
1961 PVBOXVDMA_CTL pCmd = (PVBOXVDMA_CTL)VBoxSHGSMIBufferData ((PVBOXSHGSMIHEADER)pvBuffer);
1962 vboxVDMAControl(pVGAState->pVdma, pCmd, cbBuffer - VBoxSHGSMIBufferHeaderSize());
1963 rc = VINF_SUCCESS;
1964 break;
1965 }
1966#endif
1967 case VBVA_QUERY_CONF32:
1968 {
1969 if (cbBuffer < sizeof (VBVACONF32))
1970 {
1971 rc = VERR_INVALID_PARAMETER;
1972 break;
1973 }
1974
1975 VBVACONF32 *pConf32 = (VBVACONF32 *)pvBuffer;
1976 LogFlowFunc(("VBVA_QUERY_CONF32: u32Index %d, u32Value 0x%x\n",
1977 pConf32->u32Index, pConf32->u32Value));
1978
1979 if (pConf32->u32Index == VBOX_VBVA_CONF32_MONITOR_COUNT)
1980 {
1981 pConf32->u32Value = pCtx->cViews;
1982 }
1983 else if (pConf32->u32Index == VBOX_VBVA_CONF32_HOST_HEAP_SIZE)
1984 {
1985 /* @todo a value calculated from the vram size */
1986 pConf32->u32Value = 64*_1K;
1987 }
1988 else
1989 {
1990 Log(("Unsupported VBVA_QUERY_CONF32 index %d!!!\n",
1991 pConf32->u32Index));
1992 rc = VERR_INVALID_PARAMETER;
1993 }
1994 } break;
1995
1996 case VBVA_SET_CONF32:
1997 {
1998 if (cbBuffer < sizeof (VBVACONF32))
1999 {
2000 rc = VERR_INVALID_PARAMETER;
2001 break;
2002 }
2003
2004 VBVACONF32 *pConf32 = (VBVACONF32 *)pvBuffer;
2005 LogFlowFunc(("VBVA_SET_CONF32: u32Index %d, u32Value 0x%x\n",
2006 pConf32->u32Index, pConf32->u32Value));
2007
2008 if (pConf32->u32Index == VBOX_VBVA_CONF32_MONITOR_COUNT)
2009 {
2010 /* do nothing. this is a const. */
2011 }
2012 else if (pConf32->u32Index == VBOX_VBVA_CONF32_HOST_HEAP_SIZE)
2013 {
2014 /* do nothing. this is a const. */
2015 }
2016 else
2017 {
2018 Log(("Unsupported VBVA_SET_CONF32 index %d!!!\n",
2019 pConf32->u32Index));
2020 rc = VERR_INVALID_PARAMETER;
2021 }
2022 } break;
2023
2024 case VBVA_INFO_VIEW:
2025 {
2026 if (cbBuffer < sizeof (VBVAINFOVIEW))
2027 {
2028 rc = VERR_INVALID_PARAMETER;
2029 break;
2030 }
2031
2032 /* Guest submits an array of VBVAINFOVIEW structures. */
2033 VBVAINFOVIEW *pView = (VBVAINFOVIEW *)pvBuffer;
2034
2035 for (;
2036 cbBuffer >= sizeof (VBVAINFOVIEW);
2037 pView++, cbBuffer -= sizeof (VBVAINFOVIEW))
2038 {
2039 LogFlowFunc(("VBVA_INFO_VIEW: index %d, offset 0x%x, size 0x%x, max screen size 0x%x\n",
2040 pView->u32ViewIndex, pView->u32ViewOffset, pView->u32ViewSize, pView->u32MaxScreenSize));
2041
2042 /* @todo verify view data. */
2043 if (pView->u32ViewIndex >= pCtx->cViews)
2044 {
2045 Log(("View index too large %d!!!\n",
2046 pView->u32ViewIndex));
2047 rc = VERR_INVALID_PARAMETER;
2048 break;
2049 }
2050
2051 pCtx->aViews[pView->u32ViewIndex].view = *pView;
2052 }
2053 } break;
2054
2055 case VBVA_INFO_HEAP:
2056 {
2057 if (cbBuffer < sizeof (VBVAINFOHEAP))
2058 {
2059 rc = VERR_INVALID_PARAMETER;
2060 break;
2061 }
2062
2063 VBVAINFOHEAP *pHeap = (VBVAINFOHEAP *)pvBuffer;
2064 LogFlowFunc(("VBVA_INFO_HEAP: offset 0x%x, size 0x%x\n",
2065 pHeap->u32HeapOffset, pHeap->u32HeapSize));
2066
2067 rc = HGSMISetupHostHeap (pIns, pHeap->u32HeapOffset, pHeap->u32HeapSize);
2068 } break;
2069
2070 case VBVA_FLUSH:
2071 {
2072 if (cbBuffer < sizeof (VBVAFLUSH))
2073 {
2074 rc = VERR_INVALID_PARAMETER;
2075 break;
2076 }
2077
2078 VBVAFLUSH *pFlush = (VBVAFLUSH *)pvBuffer;
2079 LogFlowFunc(("VBVA_FLUSH: u32Reserved 0x%x\n",
2080 pFlush->u32Reserved));
2081
2082 rc = vbvaFlush (pVGAState, pCtx);
2083 } break;
2084
2085 case VBVA_INFO_SCREEN:
2086 {
2087 if (cbBuffer < sizeof (VBVAINFOSCREEN))
2088 {
2089 rc = VERR_INVALID_PARAMETER;
2090 break;
2091 }
2092
2093 VBVAINFOSCREEN *pScreen = (VBVAINFOSCREEN *)pvBuffer;
2094 VBVAINFOVIEW *pView = &pCtx->aViews[pScreen->u32ViewIndex].view;
2095 /* Calculate the offset of the end of the screen so we can make
2096 * sure it is inside the view. I assume that screen rollover is not
2097 * implemented. */
2098 int64_t offEnd = (int64_t)pScreen->u32Height * pScreen->u32LineSize
2099 + pScreen->u32Width + pScreen->u32StartOffset;
2100 LogRel(("VBVA_INFO_SCREEN: [%d] @%d,%d %dx%d, line 0x%x, BPP %d, flags 0x%x\n",
2101 pScreen->u32ViewIndex, pScreen->i32OriginX, pScreen->i32OriginY,
2102 pScreen->u32Width, pScreen->u32Height,
2103 pScreen->u32LineSize, pScreen->u16BitsPerPixel, pScreen->u16Flags));
2104
2105 if ( pScreen->u32ViewIndex < RT_ELEMENTS (pCtx->aViews)
2106 && pScreen->u16BitsPerPixel <= 32
2107 && pScreen->u32Width <= UINT16_MAX
2108 && pScreen->u32Height <= UINT16_MAX
2109 && pScreen->u32LineSize <= UINT16_MAX * 4
2110 && offEnd < pView->u32MaxScreenSize)
2111 {
2112 vbvaResize (pVGAState, &pCtx->aViews[pScreen->u32ViewIndex], pScreen);
2113 }
2114 else
2115 {
2116 LogRelFlow(("VBVA_INFO_SCREEN [%lu]: bad data: %lux%lu, line 0x%lx, BPP %u, start offset %lu, max screen size %lu\n",
2117 (unsigned long)pScreen->u32ViewIndex,
2118 (unsigned long)pScreen->u32Width,
2119 (unsigned long)pScreen->u32Height,
2120 (unsigned long)pScreen->u32LineSize,
2121 (unsigned long)pScreen->u16BitsPerPixel,
2122 (unsigned long)pScreen->u32StartOffset,
2123 (unsigned long)pView->u32MaxScreenSize));
2124 rc = VERR_INVALID_PARAMETER;
2125 }
2126 } break;
2127
2128 case VBVA_ENABLE:
2129 {
2130 if (cbBuffer < sizeof (VBVAENABLE))
2131 {
2132 rc = VERR_INVALID_PARAMETER;
2133 break;
2134 }
2135
2136 VBVAENABLE *pEnable = (VBVAENABLE *)pvBuffer;
2137 unsigned uScreenId;
2138 if (pEnable->u32Flags & VBVA_F_EXTENDED)
2139 {
2140 if (cbBuffer < sizeof (VBVAENABLE_EX))
2141 {
2142 rc = VERR_INVALID_PARAMETER;
2143 break;
2144 }
2145
2146 VBVAENABLE_EX *pEnableEx = (VBVAENABLE_EX *)pvBuffer;
2147 uScreenId = pEnableEx->u32ScreenId;
2148 }
2149 else
2150 {
2151 uScreenId = vbvaViewFromOffset (pIns, pCtx, pvBuffer);
2152 }
2153
2154 if (uScreenId == ~0U)
2155 {
2156 rc = VERR_INVALID_PARAMETER;
2157 break;
2158 }
2159
2160 LogFlowFunc(("VBVA_ENABLE[%d]: u32Flags 0x%x u32Offset 0x%x\n",
2161 uScreenId, pEnable->u32Flags, pEnable->u32Offset));
2162
2163 if ((pEnable->u32Flags & (VBVA_F_ENABLE | VBVA_F_DISABLE)) == VBVA_F_ENABLE)
2164 {
2165 /* Guest reported offset relative to view. */
2166 uint32_t u32Offset = pEnable->u32Offset;
2167 if (!(pEnable->u32Flags & VBVA_F_ABSOFFSET))
2168 {
2169 u32Offset += pCtx->aViews[uScreenId].view.u32ViewOffset;
2170 }
2171
2172 VBVABUFFER *pVBVA = (VBVABUFFER *)HGSMIOffsetToPointerHost (pIns, u32Offset);
2173
2174 if (pVBVA)
2175 {
2176 /* Process any pending orders and empty the VBVA ring buffer. */
2177 vbvaFlush (pVGAState, pCtx);
2178
2179 rc = vbvaEnable (uScreenId, pVGAState, pCtx, pVBVA, u32Offset, false /* fRestored */);
2180 }
2181 else
2182 {
2183 Log(("Invalid VBVABUFFER offset 0x%x!!!\n",
2184 pEnable->u32Offset));
2185 rc = VERR_INVALID_PARAMETER;
2186 }
2187 }
2188 else if ((pEnable->u32Flags & (VBVA_F_ENABLE | VBVA_F_DISABLE)) == VBVA_F_DISABLE)
2189 {
2190 rc = vbvaDisable (uScreenId, pVGAState, pCtx);
2191 }
2192 else
2193 {
2194 Log(("Invalid VBVA_ENABLE flags 0x%x!!!\n",
2195 pEnable->u32Flags));
2196 rc = VERR_INVALID_PARAMETER;
2197 }
2198
2199 pEnable->i32Result = rc;
2200 } break;
2201
2202 case VBVA_MOUSE_POINTER_SHAPE:
2203 {
2204 if (cbBuffer < sizeof (VBVAMOUSEPOINTERSHAPE))
2205 {
2206 rc = VERR_INVALID_PARAMETER;
2207 break;
2208 }
2209
2210 VBVAMOUSEPOINTERSHAPE *pShape = (VBVAMOUSEPOINTERSHAPE *)pvBuffer;
2211
2212 LogFlowFunc(("VBVA_MOUSE_POINTER_SHAPE: i32Result 0x%x, fu32Flags 0x%x, hot spot %d,%d, size %dx%d\n",
2213 pShape->i32Result,
2214 pShape->fu32Flags,
2215 pShape->u32HotX,
2216 pShape->u32HotY,
2217 pShape->u32Width,
2218 pShape->u32Height));
2219
2220 rc = vbvaMousePointerShape (pVGAState, pCtx, pShape, cbBuffer);
2221
2222 pShape->i32Result = rc;
2223 } break;
2224
2225
2226#ifdef VBOX_WITH_VIDEOHWACCEL
2227 case VBVA_VHWA_CMD:
2228 {
2229 if (cbBuffer < sizeof (VBOXVHWACMD))
2230 {
2231 rc = VERR_INVALID_PARAMETER;
2232 break;
2233 }
2234 vbvaVHWAHandleCommand(pVGAState, (PVBOXVHWACMD)pvBuffer);
2235 rc = VINF_SUCCESS;
2236 break;
2237 } break;
2238#endif
2239
2240#ifdef VBOX_WITH_WDDM
2241 case VBVA_INFO_CAPS:
2242 {
2243 if (cbBuffer < sizeof (VBVACAPS))
2244 {
2245 rc = VERR_INVALID_PARAMETER;
2246 break;
2247 }
2248
2249 VBVACAPS *pCaps = (VBVACAPS*)pvBuffer;
2250 pVGAState->fGuestCaps = pCaps->fCaps;
2251 pCaps->rc = VINF_SUCCESS;
2252 } break;
2253#endif
2254
2255 case VBVA_CMDVBVA_ENABLE:
2256 {
2257 if (cbBuffer < sizeof (VBVAENABLE))
2258 {
2259 rc = VERR_INVALID_PARAMETER;
2260 break;
2261 }
2262
2263 VBVAENABLE *pEnable = (VBVAENABLE *)pvBuffer;
2264
2265 if ((pEnable->u32Flags & (VBVA_F_ENABLE | VBVA_F_DISABLE)) == VBVA_F_ENABLE)
2266 {
2267 uint32_t u32Offset = pEnable->u32Offset;
2268 VBVABUFFER *pVBVA = (VBVABUFFER *)HGSMIOffsetToPointerHost (pIns, u32Offset);
2269
2270 if (pVBVA)
2271 rc = vboxCmdVBVAEnable(pVGAState, pVBVA);
2272 else
2273 {
2274 LogRel(("Invalid VBVABUFFER offset 0x%x!!!\n",
2275 pEnable->u32Offset));
2276 rc = VERR_INVALID_PARAMETER;
2277 }
2278 }
2279 else if ((pEnable->u32Flags & (VBVA_F_ENABLE | VBVA_F_DISABLE)) == VBVA_F_DISABLE)
2280 {
2281 rc = vboxCmdVBVADisable(pVGAState);
2282 }
2283 else
2284 {
2285 LogRel(("Invalid VBVA_ENABLE flags 0x%x!!!\n", pEnable->u32Flags));
2286 rc = VERR_INVALID_PARAMETER;
2287 }
2288
2289 pEnable->i32Result = rc;
2290 break;
2291 }
2292 case VBVA_CMDVBVA_SUBMIT:
2293 {
2294 rc = vboxCmdVBVACmdSubmit(pVGAState);
2295 break;
2296 }
2297 case VBVA_CMDVBVA_FLUSH:
2298 {
2299 rc =vboxCmdVBVACmdFlush(pVGAState);
2300 break;
2301 }
2302 case VBVA_SCANLINE_CFG:
2303 {
2304 if (cbBuffer < sizeof (VBVASCANLINECFG))
2305 {
2306 rc = VERR_INVALID_PARAMETER;
2307 break;
2308 }
2309
2310 VBVASCANLINECFG *pCfg = (VBVASCANLINECFG*)pvBuffer;
2311 pVGAState->fScanLineCfg = pCfg->fFlags;
2312 pCfg->rc = VINF_SUCCESS;
2313 } break;
2314 default:
2315 Log(("Unsupported VBVA guest command %d!!!\n",
2316 u16ChannelInfo));
2317 break;
2318 }
2319
2320 return rc;
2321}
2322
2323void VBVAReset (PVGASTATE pVGAState)
2324{
2325 if (!pVGAState || !pVGAState->pHGSMI)
2326 {
2327 return;
2328 }
2329
2330 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pVGAState->pHGSMI);
2331
2332#ifdef VBOX_WITH_VIDEOHWACCEL
2333 vbvaVHWAReset (pVGAState);
2334#endif
2335
2336 uint32_t HgFlags = HGSMIReset (pVGAState->pHGSMI);
2337 if(HgFlags & HGSMIHOSTFLAGS_IRQ)
2338 {
2339 /* this means the IRQ is LEVEL_HIGH, need to reset it */
2340 PDMDevHlpPCISetIrq(pVGAState->pDevInsR3, 0, PDM_IRQ_LEVEL_LOW);
2341 }
2342
2343 if (pCtx)
2344 {
2345 vbvaFlush (pVGAState, pCtx);
2346
2347 unsigned uScreenId;
2348
2349 for (uScreenId = 0; uScreenId < pCtx->cViews; uScreenId++)
2350 {
2351 vbvaDisable (uScreenId, pVGAState, pCtx);
2352 }
2353
2354 pCtx->mouseShapeInfo.fSet = false;
2355 RTMemFree(pCtx->mouseShapeInfo.pu8Shape);
2356 pCtx->mouseShapeInfo.pu8Shape = NULL;
2357 pCtx->mouseShapeInfo.cbAllocated = 0;
2358 pCtx->mouseShapeInfo.cbShape = 0;
2359 }
2360
2361}
2362
2363int VBVAUpdateDisplay (PVGASTATE pVGAState)
2364{
2365 int rc = VERR_NOT_SUPPORTED; /* Assuming that the VGA device will have to do updates. */
2366
2367 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pVGAState->pHGSMI);
2368
2369 if (pCtx)
2370 {
2371 rc = vbvaFlush (pVGAState, pCtx);
2372
2373 if (RT_SUCCESS (rc))
2374 {
2375 if (!pCtx->aViews[0].pVBVA)
2376 {
2377 /* VBVA is not enabled for the first view, so VGA device must do updates. */
2378 rc = VERR_NOT_SUPPORTED;
2379 }
2380 }
2381 }
2382
2383 return rc;
2384}
2385
2386static HGSMICHANNELHANDLER sOldChannelHandler;
2387
2388int VBVAInit (PVGASTATE pVGAState)
2389{
2390 PPDMDEVINS pDevIns = pVGAState->pDevInsR3;
2391
2392 PVM pVM = PDMDevHlpGetVM(pDevIns);
2393
2394 int rc = HGSMICreate (&pVGAState->pHGSMI,
2395 pVM,
2396 "VBVA",
2397 0,
2398 pVGAState->vram_ptrR3,
2399 pVGAState->vram_size,
2400 vbvaNotifyGuest,
2401 pVGAState,
2402 sizeof (VBVACONTEXT));
2403
2404 if (RT_SUCCESS (rc))
2405 {
2406 rc = HGSMIHostChannelRegister (pVGAState->pHGSMI,
2407 HGSMI_CH_VBVA,
2408 vbvaChannelHandler,
2409 pVGAState,
2410 &sOldChannelHandler);
2411 if (RT_SUCCESS (rc))
2412 {
2413 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pVGAState->pHGSMI);
2414 pCtx->cViews = pVGAState->cMonitors;
2415 }
2416 }
2417
2418 return rc;
2419
2420}
2421
2422void VBVADestroy (PVGASTATE pVGAState)
2423{
2424 VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pVGAState->pHGSMI);
2425
2426 if (pCtx)
2427 {
2428 pCtx->mouseShapeInfo.fSet = false;
2429 RTMemFree(pCtx->mouseShapeInfo.pu8Shape);
2430 pCtx->mouseShapeInfo.pu8Shape = NULL;
2431 pCtx->mouseShapeInfo.cbAllocated = 0;
2432 pCtx->mouseShapeInfo.cbShape = 0;
2433 }
2434
2435 HGSMIDestroy (pVGAState->pHGSMI);
2436 pVGAState->pHGSMI = NULL;
2437}
Note: See TracBrowser for help on using the repository browser.

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