VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/DisplayImplLegacy.cpp@ 61644

Last change on this file since 61644 was 55988, checked in by vboxsync, 10 years ago

iprt/log.h,SUPDrv: Replaced the 'personal' logging groups with 6 more generic logging levels (7 thru 12) and a 'Warn' level. The 'Warn' level is enabled by 'group.e' together with level 1 logging. Modified the new RTLog[Rel][Get]DefaultInstanceEx functions to only take one 32-bit parameter to minimize call setup time and size. Major support driver version bump. LogAleksey=Log7, LogBird=Log8, LogSunlover=Log9, none of the other personal macros was used. Log*Warning got renamed to Log1*Warning so as to not confuse it with the LogWarn/LogRelWarn macros.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.7 KB
Line 
1/* $Id: DisplayImplLegacy.cpp 55988 2015-05-20 23:24:44Z vboxsync $ */
2/** @file
3 * VirtualBox IDisplay implementation
4 *
5 * Methods and helpers to support old guest additions 3.x or older.
6 * This is not used by the current guest additions.
7 */
8
9/*
10 * Copyright (C) 2006-2014 Oracle Corporation
11 *
12 * This file is part of VirtualBox Open Source Edition (OSE), as
13 * available from http://www.virtualbox.org. This file is free software;
14 * you can redistribute it and/or modify it under the terms of the GNU
15 * General Public License (GPL) as published by the Free Software
16 * Foundation, in version 2 as it comes in the "COPYING" file of the
17 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
18 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
19 */
20
21#include "DisplayImpl.h"
22#include "ConsoleImpl.h"
23#include "ConsoleVRDPServer.h"
24#include "VMMDev.h"
25
26#include "Logging.h"
27
28/* generated header */
29#include "VBoxEvents.h"
30
31
32int videoAccelConstruct(VIDEOACCEL *pVideoAccel)
33{
34 pVideoAccel->pVbvaMemory = NULL;
35 pVideoAccel->fVideoAccelEnabled = false;
36
37 pVideoAccel->pu8VbvaPartial = NULL;
38 pVideoAccel->cbVbvaPartial = 0;
39
40 pVideoAccel->hXRoadsVideoAccel = NIL_RTSEMXROADS;
41 int rc = RTSemXRoadsCreate(&pVideoAccel->hXRoadsVideoAccel);
42 AssertRC(rc);
43
44 return rc;
45}
46
47void videoAccelDestroy(VIDEOACCEL *pVideoAccel)
48{
49 RTSemXRoadsDestroy(pVideoAccel->hXRoadsVideoAccel);
50 RT_ZERO(*pVideoAccel);
51}
52
53static unsigned mapCoordsToScreen(DISPLAYFBINFO *pInfos, unsigned cInfos, int *px, int *py, int *pw, int *ph)
54{
55 DISPLAYFBINFO *pInfo = pInfos;
56 unsigned uScreenId;
57 Log9(("mapCoordsToScreen: %d,%d %dx%d\n", *px, *py, *pw, *ph));
58 for (uScreenId = 0; uScreenId < cInfos; uScreenId++, pInfo++)
59 {
60 Log9((" [%d] %d,%d %dx%d\n", uScreenId, pInfo->xOrigin, pInfo->yOrigin, pInfo->w, pInfo->h));
61 if ( (pInfo->xOrigin <= *px && *px < pInfo->xOrigin + (int)pInfo->w)
62 && (pInfo->yOrigin <= *py && *py < pInfo->yOrigin + (int)pInfo->h))
63 {
64 /* The rectangle belongs to the screen. Correct coordinates. */
65 *px -= pInfo->xOrigin;
66 *py -= pInfo->yOrigin;
67 Log9((" -> %d,%d", *px, *py));
68 break;
69 }
70 }
71 if (uScreenId == cInfos)
72 {
73 /* Map to primary screen. */
74 uScreenId = 0;
75 }
76 Log9((" scr %d\n", uScreenId));
77 return uScreenId;
78}
79
80
81typedef struct _VBVADIRTYREGION
82{
83 /* Copies of object's pointers used by vbvaRgn functions. */
84 DISPLAYFBINFO *paFramebuffers;
85 unsigned cMonitors;
86 Display *pDisplay;
87 PPDMIDISPLAYPORT pPort;
88
89 /* The rectangle that includes all dirty rectangles. */
90 RTRECT aDirtyRects[SchemaDefs::MaxGuestMonitors];
91
92} VBVADIRTYREGION;
93
94static void vbvaRgnInit(VBVADIRTYREGION *prgn, DISPLAYFBINFO *paFramebuffers, unsigned cMonitors,
95 Display *pd, PPDMIDISPLAYPORT pp)
96{
97 prgn->paFramebuffers = paFramebuffers;
98 prgn->cMonitors = cMonitors;
99 prgn->pDisplay = pd;
100 prgn->pPort = pp;
101
102 RT_ZERO(prgn->aDirtyRects);
103}
104
105static void vbvaRgnDirtyRect(VBVADIRTYREGION *prgn, unsigned uScreenId, VBVACMDHDR *phdr)
106{
107 Log9(("x = %d, y = %d, w = %d, h = %d\n", phdr->x, phdr->y, phdr->w, phdr->h));
108
109 /*
110 * Here update rectangles are accumulated to form an update area.
111 */
112 /** @todo
113 * Now the simplest method is used which builds one rectangle that
114 * includes all update areas. A bit more advanced method can be
115 * employed here. The method should be fast however.
116 */
117 if (phdr->w == 0 || phdr->h == 0)
118 {
119 /* Empty rectangle. */
120 return;
121 }
122
123 int32_t xRight = phdr->x + phdr->w;
124 int32_t yBottom = phdr->y + phdr->h;
125
126 RTRECT *pDirtyRect = &prgn->aDirtyRects[uScreenId];
127 DISPLAYFBINFO *pFBInfo = &prgn->paFramebuffers[uScreenId];
128
129 if (pDirtyRect->xRight == 0)
130 {
131 /* This is the first rectangle to be added. */
132 pDirtyRect->xLeft = phdr->x;
133 pDirtyRect->yTop = phdr->y;
134 pDirtyRect->xRight = xRight;
135 pDirtyRect->yBottom = yBottom;
136 }
137 else
138 {
139 /* Adjust region coordinates. */
140 if (pDirtyRect->xLeft > phdr->x)
141 {
142 pDirtyRect->xLeft = phdr->x;
143 }
144
145 if (pDirtyRect->yTop > phdr->y)
146 {
147 pDirtyRect->yTop = phdr->y;
148 }
149
150 if (pDirtyRect->xRight < xRight)
151 {
152 pDirtyRect->xRight = xRight;
153 }
154
155 if (pDirtyRect->yBottom < yBottom)
156 {
157 pDirtyRect->yBottom = yBottom;
158 }
159 }
160
161 if (pFBInfo->fDefaultFormat)
162 {
163 //@todo pfnUpdateDisplayRect must take the vram offset parameter for the framebuffer
164 prgn->pPort->pfnUpdateDisplayRect(prgn->pPort, phdr->x, phdr->y, phdr->w, phdr->h);
165 prgn->pDisplay->i_handleDisplayUpdate(uScreenId, phdr->x, phdr->y, phdr->w, phdr->h);
166 }
167
168 return;
169}
170
171static void vbvaRgnUpdateFramebuffer(VBVADIRTYREGION *prgn, unsigned uScreenId)
172{
173 RTRECT *pDirtyRect = &prgn->aDirtyRects[uScreenId];
174 DISPLAYFBINFO *pFBInfo = &prgn->paFramebuffers[uScreenId];
175
176 uint32_t w = pDirtyRect->xRight - pDirtyRect->xLeft;
177 uint32_t h = pDirtyRect->yBottom - pDirtyRect->yTop;
178
179 if (!pFBInfo->fDefaultFormat && w != 0 && h != 0)
180 {
181 //@todo pfnUpdateDisplayRect must take the vram offset parameter for the framebuffer
182 prgn->pPort->pfnUpdateDisplayRect(prgn->pPort, pDirtyRect->xLeft, pDirtyRect->yTop, w, h);
183 prgn->pDisplay->i_handleDisplayUpdate(uScreenId, pDirtyRect->xLeft, pDirtyRect->yTop, w, h);
184 }
185}
186
187void i_vbvaSetMemoryFlags(VBVAMEMORY *pVbvaMemory,
188 bool fVideoAccelEnabled,
189 bool fVideoAccelVRDP,
190 uint32_t fu32SupportedOrders,
191 DISPLAYFBINFO *paFBInfos,
192 unsigned cFBInfos)
193{
194 if (pVbvaMemory)
195 {
196 /* This called only on changes in mode. So reset VRDP always. */
197 uint32_t fu32Flags = VBVA_F_MODE_VRDP_RESET;
198
199 if (fVideoAccelEnabled)
200 {
201 fu32Flags |= VBVA_F_MODE_ENABLED;
202
203 if (fVideoAccelVRDP)
204 {
205 fu32Flags |= VBVA_F_MODE_VRDP | VBVA_F_MODE_VRDP_ORDER_MASK;
206
207 pVbvaMemory->fu32SupportedOrders = fu32SupportedOrders;
208 }
209 }
210
211 pVbvaMemory->fu32ModeFlags = fu32Flags;
212 }
213
214 unsigned uScreenId;
215 for (uScreenId = 0; uScreenId < cFBInfos; uScreenId++)
216 {
217 if (paFBInfos[uScreenId].pHostEvents)
218 {
219 paFBInfos[uScreenId].pHostEvents->fu32Events |= VBOX_VIDEO_INFO_HOST_EVENTS_F_VRDP_RESET;
220 }
221 }
222}
223
224bool Display::i_VideoAccelAllowed(void)
225{
226 return true;
227}
228
229int videoAccelEnterVGA(VIDEOACCEL *pVideoAccel)
230{
231 return RTSemXRoadsNSEnter(pVideoAccel->hXRoadsVideoAccel);
232}
233
234void videoAccelLeaveVGA(VIDEOACCEL *pVideoAccel)
235{
236 RTSemXRoadsNSLeave(pVideoAccel->hXRoadsVideoAccel);
237}
238
239int videoAccelEnterVMMDev(VIDEOACCEL *pVideoAccel)
240{
241 return RTSemXRoadsEWEnter(pVideoAccel->hXRoadsVideoAccel);
242}
243
244void videoAccelLeaveVMMDev(VIDEOACCEL *pVideoAccel)
245{
246 RTSemXRoadsEWLeave(pVideoAccel->hXRoadsVideoAccel);
247}
248
249/**
250 * @thread EMT
251 */
252int Display::i_VideoAccelEnable(bool fEnable, VBVAMEMORY *pVbvaMemory, PPDMIDISPLAYPORT pUpPort)
253{
254 int rc;
255 LogRelFlowFunc(("fEnable = %d\n", fEnable));
256
257 rc = i_videoAccelEnable(fEnable, pVbvaMemory, pUpPort);
258
259 LogRelFlowFunc(("%Rrc.\n", rc));
260 return rc;
261}
262
263int Display::i_videoAccelEnable(bool fEnable, VBVAMEMORY *pVbvaMemory, PPDMIDISPLAYPORT pUpPort)
264{
265 int rc = VINF_SUCCESS;
266
267 VIDEOACCEL *pVideoAccel = &mVideoAccelLegacy;
268
269 /* Called each time the guest wants to use acceleration,
270 * or when the VGA device disables acceleration,
271 * or when restoring the saved state with accel enabled.
272 *
273 * VGA device disables acceleration on each video mode change
274 * and on reset.
275 *
276 * Guest enabled acceleration at will. And it has to enable
277 * acceleration after a mode change.
278 */
279 LogRelFlowFunc(("mfVideoAccelEnabled = %d, fEnable = %d, pVbvaMemory = %p\n",
280 pVideoAccel->fVideoAccelEnabled, fEnable, pVbvaMemory));
281
282 /* Strictly check parameters. Callers must not pass anything in the case. */
283 Assert((fEnable && pVbvaMemory) || (!fEnable && pVbvaMemory == NULL));
284
285 if (!i_VideoAccelAllowed ())
286 return VERR_NOT_SUPPORTED;
287
288 /* Check that current status is not being changed */
289 if (pVideoAccel->fVideoAccelEnabled == fEnable)
290 return rc;
291
292 if (pVideoAccel->fVideoAccelEnabled)
293 {
294 /* Process any pending orders and empty the VBVA ring buffer. */
295 i_videoAccelFlush (pUpPort);
296 }
297
298 if (!fEnable && pVideoAccel->pVbvaMemory)
299 pVideoAccel->pVbvaMemory->fu32ModeFlags &= ~VBVA_F_MODE_ENABLED;
300
301 if (fEnable)
302 {
303 /* Process any pending VGA device changes, resize. */
304 pUpPort->pfnUpdateDisplayAll(pUpPort, /* fFailOnResize = */ false);
305 }
306
307 /* Protect the videoaccel state transition. */
308 RTCritSectEnter(&mVideoAccelLock);
309
310 if (fEnable)
311 {
312 /* Initialize the hardware memory. */
313 i_vbvaSetMemoryFlags(pVbvaMemory, true, mfVideoAccelVRDP,
314 mfu32SupportedOrders, maFramebuffers, mcMonitors);
315 pVbvaMemory->off32Data = 0;
316 pVbvaMemory->off32Free = 0;
317
318 memset(pVbvaMemory->aRecords, 0, sizeof(pVbvaMemory->aRecords));
319 pVbvaMemory->indexRecordFirst = 0;
320 pVbvaMemory->indexRecordFree = 0;
321
322 pVideoAccel->pVbvaMemory = pVbvaMemory;
323 pVideoAccel->fVideoAccelEnabled = true;
324
325 LogRel(("VBVA: Enabled.\n"));
326 }
327 else
328 {
329 pVideoAccel->pVbvaMemory = NULL;
330 pVideoAccel->fVideoAccelEnabled = false;
331
332 LogRel(("VBVA: Disabled.\n"));
333 }
334
335 RTCritSectLeave(&mVideoAccelLock);
336
337 if (!fEnable)
338 {
339 pUpPort->pfnUpdateDisplayAll(pUpPort, /* fFailOnResize = */ false);
340 }
341
342 /* Notify the VMMDev, which saves VBVA status in the saved state,
343 * and needs to know current status.
344 */
345 VMMDev *pVMMDev = mParent->i_getVMMDev();
346 if (pVMMDev)
347 {
348 PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
349 if (pVMMDevPort)
350 pVMMDevPort->pfnVBVAChange(pVMMDevPort, fEnable);
351 }
352
353 LogRelFlowFunc(("%Rrc.\n", rc));
354 return rc;
355}
356
357static bool i_vbvaVerifyRingBuffer(VBVAMEMORY *pVbvaMemory)
358{
359 return true;
360}
361
362static void i_vbvaFetchBytes(VBVAMEMORY *pVbvaMemory, uint8_t *pu8Dst, uint32_t cbDst)
363{
364 if (cbDst >= VBVA_RING_BUFFER_SIZE)
365 {
366 AssertMsgFailed(("cbDst = 0x%08X, ring buffer size 0x%08X\n", cbDst, VBVA_RING_BUFFER_SIZE));
367 return;
368 }
369
370 uint32_t u32BytesTillBoundary = VBVA_RING_BUFFER_SIZE - pVbvaMemory->off32Data;
371 uint8_t *src = &pVbvaMemory->au8RingBuffer[pVbvaMemory->off32Data];
372 int32_t i32Diff = cbDst - u32BytesTillBoundary;
373
374 if (i32Diff <= 0)
375 {
376 /* Chunk will not cross buffer boundary. */
377 memcpy (pu8Dst, src, cbDst);
378 }
379 else
380 {
381 /* Chunk crosses buffer boundary. */
382 memcpy(pu8Dst, src, u32BytesTillBoundary);
383 memcpy(pu8Dst + u32BytesTillBoundary, &pVbvaMemory->au8RingBuffer[0], i32Diff);
384 }
385
386 /* Advance data offset. */
387 pVbvaMemory->off32Data = (pVbvaMemory->off32Data + cbDst) % VBVA_RING_BUFFER_SIZE;
388
389 return;
390}
391
392
393static bool i_vbvaPartialRead(uint8_t **ppu8, uint32_t *pcb, uint32_t cbRecord, VBVAMEMORY *pVbvaMemory)
394{
395 uint8_t *pu8New;
396
397 LogFlow(("MAIN::DisplayImpl::vbvaPartialRead: p = %p, cb = %d, cbRecord 0x%08X\n",
398 *ppu8, *pcb, cbRecord));
399
400 if (*ppu8)
401 {
402 Assert (*pcb);
403 pu8New = (uint8_t *)RTMemRealloc(*ppu8, cbRecord);
404 }
405 else
406 {
407 Assert (!*pcb);
408 pu8New = (uint8_t *)RTMemAlloc(cbRecord);
409 }
410
411 if (!pu8New)
412 {
413 /* Memory allocation failed, fail the function. */
414 Log(("MAIN::vbvaPartialRead: failed to (re)alocate memory for partial record!!! cbRecord 0x%08X\n",
415 cbRecord));
416
417 if (*ppu8)
418 {
419 RTMemFree(*ppu8);
420 }
421
422 *ppu8 = NULL;
423 *pcb = 0;
424
425 return false;
426 }
427
428 /* Fetch data from the ring buffer. */
429 i_vbvaFetchBytes(pVbvaMemory, pu8New + *pcb, cbRecord - *pcb);
430
431 *ppu8 = pu8New;
432 *pcb = cbRecord;
433
434 return true;
435}
436
437/* For contiguous chunks just return the address in the buffer.
438 * For crossing boundary - allocate a buffer from heap.
439 */
440static bool i_vbvaFetchCmd(VIDEOACCEL *pVideoAccel, VBVACMDHDR **ppHdr, uint32_t *pcbCmd)
441{
442 VBVAMEMORY *pVbvaMemory = pVideoAccel->pVbvaMemory;
443
444 uint32_t indexRecordFirst = pVbvaMemory->indexRecordFirst;
445 uint32_t indexRecordFree = pVbvaMemory->indexRecordFree;
446
447#ifdef DEBUG_sunlover
448 LogFlowFunc(("first = %d, free = %d\n",
449 indexRecordFirst, indexRecordFree));
450#endif /* DEBUG_sunlover */
451
452 if (!i_vbvaVerifyRingBuffer(pVbvaMemory))
453 {
454 return false;
455 }
456
457 if (indexRecordFirst == indexRecordFree)
458 {
459 /* No records to process. Return without assigning output variables. */
460 return true;
461 }
462
463 uint32_t cbRecordCurrent = ASMAtomicReadU32(&pVbvaMemory->aRecords[indexRecordFirst].cbRecord);
464
465#ifdef DEBUG_sunlover
466 LogFlowFunc(("cbRecord = 0x%08X\n", cbRecordCurrent));
467#endif /* DEBUG_sunlover */
468
469 uint32_t cbRecord = cbRecordCurrent & ~VBVA_F_RECORD_PARTIAL;
470
471 if (pVideoAccel->cbVbvaPartial)
472 {
473 /* There is a partial read in process. Continue with it. */
474
475 Assert(pVideoAccel->pu8VbvaPartial);
476
477 LogFlowFunc(("continue partial record cbVbvaPartial = %d cbRecord 0x%08X, first = %d, free = %d\n",
478 pVideoAccel->cbVbvaPartial, cbRecordCurrent, indexRecordFirst, indexRecordFree));
479
480 if (cbRecord > pVideoAccel->cbVbvaPartial)
481 {
482 /* New data has been added to the record. */
483 if (!i_vbvaPartialRead(&pVideoAccel->pu8VbvaPartial, &pVideoAccel->cbVbvaPartial, cbRecord, pVbvaMemory))
484 {
485 return false;
486 }
487 }
488
489 if (!(cbRecordCurrent & VBVA_F_RECORD_PARTIAL))
490 {
491 /* The record is completed by guest. Return it to the caller. */
492 *ppHdr = (VBVACMDHDR *)pVideoAccel->pu8VbvaPartial;
493 *pcbCmd = pVideoAccel->cbVbvaPartial;
494
495 pVideoAccel->pu8VbvaPartial = NULL;
496 pVideoAccel->cbVbvaPartial = 0;
497
498 /* Advance the record index. */
499 pVbvaMemory->indexRecordFirst = (indexRecordFirst + 1) % VBVA_MAX_RECORDS;
500
501#ifdef DEBUG_sunlover
502 LogFlowFunc(("partial done ok, data = %d, free = %d\n",
503 pVbvaMemory->off32Data, pVbvaMemory->off32Free));
504#endif /* DEBUG_sunlover */
505 }
506
507 return true;
508 }
509
510 /* A new record need to be processed. */
511 if (cbRecordCurrent & VBVA_F_RECORD_PARTIAL)
512 {
513 /* Current record is being written by guest. '=' is important here. */
514 if (cbRecord >= VBVA_RING_BUFFER_SIZE - VBVA_RING_BUFFER_THRESHOLD)
515 {
516 /* Partial read must be started. */
517 if (!i_vbvaPartialRead(&pVideoAccel->pu8VbvaPartial, &pVideoAccel->cbVbvaPartial, cbRecord, pVbvaMemory))
518 {
519 return false;
520 }
521
522 LogFlowFunc(("started partial record cbVbvaPartial = 0x%08X cbRecord 0x%08X, first = %d, free = %d\n",
523 pVideoAccel->cbVbvaPartial, cbRecordCurrent, indexRecordFirst, indexRecordFree));
524 }
525
526 return true;
527 }
528
529 /* Current record is complete. If it is not empty, process it. */
530 if (cbRecord)
531 {
532 /* The size of largest contiguous chunk in the ring biffer. */
533 uint32_t u32BytesTillBoundary = VBVA_RING_BUFFER_SIZE - pVbvaMemory->off32Data;
534
535 /* The ring buffer pointer. */
536 uint8_t *au8RingBuffer = &pVbvaMemory->au8RingBuffer[0];
537
538 /* The pointer to data in the ring buffer. */
539 uint8_t *src = &au8RingBuffer[pVbvaMemory->off32Data];
540
541 /* Fetch or point the data. */
542 if (u32BytesTillBoundary >= cbRecord)
543 {
544 /* The command does not cross buffer boundary. Return address in the buffer. */
545 *ppHdr = (VBVACMDHDR *)src;
546
547 /* Advance data offset. */
548 pVbvaMemory->off32Data = (pVbvaMemory->off32Data + cbRecord) % VBVA_RING_BUFFER_SIZE;
549 }
550 else
551 {
552 /* The command crosses buffer boundary. Rare case, so not optimized. */
553 uint8_t *dst = (uint8_t *)RTMemAlloc(cbRecord);
554
555 if (!dst)
556 {
557 LogRelFlowFunc(("could not allocate %d bytes from heap!!!\n", cbRecord));
558 pVbvaMemory->off32Data = (pVbvaMemory->off32Data + cbRecord) % VBVA_RING_BUFFER_SIZE;
559 return false;
560 }
561
562 i_vbvaFetchBytes(pVbvaMemory, dst, cbRecord);
563
564 *ppHdr = (VBVACMDHDR *)dst;
565
566#ifdef DEBUG_sunlover
567 LogFlowFunc(("Allocated from heap %p\n", dst));
568#endif /* DEBUG_sunlover */
569 }
570 }
571
572 *pcbCmd = cbRecord;
573
574 /* Advance the record index. */
575 pVbvaMemory->indexRecordFirst = (indexRecordFirst + 1) % VBVA_MAX_RECORDS;
576
577#ifdef DEBUG_sunlover
578 LogFlowFunc(("done ok, data = %d, free = %d\n",
579 pVbvaMemory->off32Data, pVbvaMemory->off32Free));
580#endif /* DEBUG_sunlover */
581
582 return true;
583}
584
585static void i_vbvaReleaseCmd(VIDEOACCEL *pVideoAccel, VBVACMDHDR *pHdr, int32_t cbCmd)
586{
587 uint8_t *au8RingBuffer = pVideoAccel->pVbvaMemory->au8RingBuffer;
588
589 if ( (uint8_t *)pHdr >= au8RingBuffer
590 && (uint8_t *)pHdr < &au8RingBuffer[VBVA_RING_BUFFER_SIZE])
591 {
592 /* The pointer is inside ring buffer. Must be continuous chunk. */
593 Assert(VBVA_RING_BUFFER_SIZE - ((uint8_t *)pHdr - au8RingBuffer) >= cbCmd);
594
595 /* Do nothing. */
596
597 Assert(!pVideoAccel->pu8VbvaPartial && pVideoAccel->cbVbvaPartial == 0);
598 }
599 else
600 {
601 /* The pointer is outside. It is then an allocated copy. */
602
603#ifdef DEBUG_sunlover
604 LogFlowFunc(("Free heap %p\n", pHdr));
605#endif /* DEBUG_sunlover */
606
607 if ((uint8_t *)pHdr == pVideoAccel->pu8VbvaPartial)
608 {
609 pVideoAccel->pu8VbvaPartial = NULL;
610 pVideoAccel->cbVbvaPartial = 0;
611 }
612 else
613 {
614 Assert(!pVideoAccel->pu8VbvaPartial && pVideoAccel->cbVbvaPartial == 0);
615 }
616
617 RTMemFree(pHdr);
618 }
619
620 return;
621}
622
623
624/**
625 * Called regularly on the DisplayRefresh timer.
626 * Also on behalf of guest, when the ring buffer is full.
627 *
628 * @thread EMT
629 */
630void Display::i_VideoAccelFlush(PPDMIDISPLAYPORT pUpPort)
631{
632 int rc = i_videoAccelFlush(pUpPort);
633 if (RT_FAILURE(rc))
634 {
635 /* Disable on errors. */
636 i_videoAccelEnable(false, NULL, pUpPort);
637 }
638}
639
640int Display::i_videoAccelFlush(PPDMIDISPLAYPORT pUpPort)
641{
642 VIDEOACCEL *pVideoAccel = &mVideoAccelLegacy;
643 VBVAMEMORY *pVbvaMemory = pVideoAccel->pVbvaMemory;
644
645#ifdef DEBUG_sunlover_2
646 LogFlowFunc(("fVideoAccelEnabled = %d\n", pVideoAccel->fVideoAccelEnabled));
647#endif /* DEBUG_sunlover_2 */
648
649 if (!pVideoAccel->fVideoAccelEnabled)
650 {
651 Log(("Display::VideoAccelFlush: called with disabled VBVA!!! Ignoring.\n"));
652 return VINF_SUCCESS;
653 }
654
655 /* Here VBVA is enabled and we have the accelerator memory pointer. */
656 Assert(pVbvaMemory);
657
658#ifdef DEBUG_sunlover_2
659 LogFlowFunc(("indexRecordFirst = %d, indexRecordFree = %d, off32Data = %d, off32Free = %d\n",
660 pVbvaMemory->indexRecordFirst, pVbvaMemory->indexRecordFree,
661 pVbvaMemory->off32Data, pVbvaMemory->off32Free));
662#endif /* DEBUG_sunlover_2 */
663
664 /* Quick check for "nothing to update" case. */
665 if (pVbvaMemory->indexRecordFirst == pVbvaMemory->indexRecordFree)
666 {
667 return VINF_SUCCESS;
668 }
669
670 /* Process the ring buffer */
671 unsigned uScreenId;
672
673 /* Initialize dirty rectangles accumulator. */
674 VBVADIRTYREGION rgn;
675 vbvaRgnInit(&rgn, maFramebuffers, mcMonitors, this, pUpPort);
676
677 for (;;)
678 {
679 VBVACMDHDR *phdr = NULL;
680 uint32_t cbCmd = ~0;
681
682 /* Fetch the command data. */
683 if (!i_vbvaFetchCmd(pVideoAccel, &phdr, &cbCmd))
684 {
685 Log(("Display::VideoAccelFlush: unable to fetch command. off32Data = %d, off32Free = %d. Disabling VBVA!!!\n",
686 pVbvaMemory->off32Data, pVbvaMemory->off32Free));
687 return VERR_INVALID_STATE;
688 }
689
690 if (cbCmd == uint32_t(~0))
691 {
692 /* No more commands yet in the queue. */
693#ifdef DEBUG_sunlover
694 LogFlowFunc(("no command\n"));
695#endif /* DEBUG_sunlover */
696 break;
697 }
698
699 if (cbCmd != 0)
700 {
701#ifdef DEBUG_sunlover
702 LogFlowFunc(("hdr: cbCmd = %d, x=%d, y=%d, w=%d, h=%d\n",
703 cbCmd, phdr->x, phdr->y, phdr->w, phdr->h));
704#endif /* DEBUG_sunlover */
705
706 VBVACMDHDR hdrSaved = *phdr;
707
708 int x = phdr->x;
709 int y = phdr->y;
710 int w = phdr->w;
711 int h = phdr->h;
712
713 uScreenId = mapCoordsToScreen(maFramebuffers, mcMonitors, &x, &y, &w, &h);
714
715 phdr->x = (int16_t)x;
716 phdr->y = (int16_t)y;
717 phdr->w = (uint16_t)w;
718 phdr->h = (uint16_t)h;
719
720 DISPLAYFBINFO *pFBInfo = &maFramebuffers[uScreenId];
721
722 /* Handle the command.
723 *
724 * Guest is responsible for updating the guest video memory.
725 * The Windows guest does all drawing using Eng*.
726 *
727 * For local output, only dirty rectangle information is used
728 * to update changed areas.
729 *
730 * Dirty rectangles are accumulated to exclude overlapping updates and
731 * group small updates to a larger one.
732 */
733
734 /* Accumulate the update. */
735 vbvaRgnDirtyRect(&rgn, uScreenId, phdr);
736
737 /* Forward the command to VRDP server. */
738 mParent->i_consoleVRDPServer()->SendUpdate(uScreenId, phdr, cbCmd);
739
740 *phdr = hdrSaved;
741 }
742
743 i_vbvaReleaseCmd(pVideoAccel, phdr, cbCmd);
744 }
745
746 for (uScreenId = 0; uScreenId < mcMonitors; uScreenId++)
747 {
748 /* Draw the framebuffer. */
749 vbvaRgnUpdateFramebuffer(&rgn, uScreenId);
750 }
751 return VINF_SUCCESS;
752}
753
754int Display::i_videoAccelRefreshProcess(PPDMIDISPLAYPORT pUpPort)
755{
756 int rc = VWRN_INVALID_STATE; /* Default is to do a display update in VGA device. */
757
758 VIDEOACCEL *pVideoAccel = &mVideoAccelLegacy;
759
760 videoAccelEnterVGA(pVideoAccel);
761
762 if (pVideoAccel->fVideoAccelEnabled)
763 {
764 Assert(pVideoAccel->pVbvaMemory);
765 rc = i_videoAccelFlush(pUpPort);
766 if (RT_FAILURE(rc))
767 {
768 /* Disable on errors. */
769 i_videoAccelEnable(false, NULL, pUpPort);
770 rc = VWRN_INVALID_STATE; /* Do a display update in VGA device. */
771 }
772 else
773 {
774 rc = VINF_SUCCESS;
775 }
776 }
777
778 videoAccelLeaveVGA(pVideoAccel);
779
780 return rc;
781}
782
783void Display::processAdapterData(void *pvVRAM, uint32_t u32VRAMSize)
784{
785 if (pvVRAM == NULL)
786 {
787 unsigned i;
788 for (i = 0; i < mcMonitors; i++)
789 {
790 DISPLAYFBINFO *pFBInfo = &maFramebuffers[i];
791
792 pFBInfo->u32Offset = 0;
793 pFBInfo->u32MaxFramebufferSize = 0;
794 pFBInfo->u32InformationSize = 0;
795 }
796 }
797#ifndef VBOX_WITH_HGSMI
798 else
799 {
800 uint8_t *pu8 = (uint8_t *)pvVRAM;
801 pu8 += u32VRAMSize - VBOX_VIDEO_ADAPTER_INFORMATION_SIZE;
802
803 // @todo
804 uint8_t *pu8End = pu8 + VBOX_VIDEO_ADAPTER_INFORMATION_SIZE;
805
806 VBOXVIDEOINFOHDR *pHdr;
807
808 for (;;)
809 {
810 pHdr = (VBOXVIDEOINFOHDR *)pu8;
811 pu8 += sizeof(VBOXVIDEOINFOHDR);
812
813 if (pu8 >= pu8End)
814 {
815 LogRel(("VBoxVideo: Guest adapter information overflow!!!\n"));
816 break;
817 }
818
819 if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_DISPLAY)
820 {
821 if (pHdr->u16Length != sizeof(VBOXVIDEOINFODISPLAY))
822 {
823 LogRel(("VBoxVideo: Guest adapter information %s invalid length %d!!!\n", "DISPLAY", pHdr->u16Length));
824 break;
825 }
826
827 VBOXVIDEOINFODISPLAY *pDisplay = (VBOXVIDEOINFODISPLAY *)pu8;
828
829 if (pDisplay->u32Index >= mcMonitors)
830 {
831 LogRel(("VBoxVideo: Guest adapter information invalid display index %d!!!\n", pDisplay->u32Index));
832 break;
833 }
834
835 DISPLAYFBINFO *pFBInfo = &maFramebuffers[pDisplay->u32Index];
836
837 pFBInfo->u32Offset = pDisplay->u32Offset;
838 pFBInfo->u32MaxFramebufferSize = pDisplay->u32FramebufferSize;
839 pFBInfo->u32InformationSize = pDisplay->u32InformationSize;
840
841 LogRelFlow(("VBOX_VIDEO_INFO_TYPE_DISPLAY: %d: at 0x%08X, size 0x%08X, info 0x%08X\n", pDisplay->u32Index,
842 pDisplay->u32Offset, pDisplay->u32FramebufferSize, pDisplay->u32InformationSize));
843 }
844 else if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_QUERY_CONF32)
845 {
846 if (pHdr->u16Length != sizeof(VBOXVIDEOINFOQUERYCONF32))
847 {
848 LogRel(("VBoxVideo: Guest adapter information %s invalid length %d!!!\n", "CONF32", pHdr->u16Length));
849 break;
850 }
851
852 VBOXVIDEOINFOQUERYCONF32 *pConf32 = (VBOXVIDEOINFOQUERYCONF32 *)pu8;
853
854 switch (pConf32->u32Index)
855 {
856 case VBOX_VIDEO_QCI32_MONITOR_COUNT:
857 {
858 pConf32->u32Value = mcMonitors;
859 } break;
860
861 case VBOX_VIDEO_QCI32_OFFSCREEN_HEAP_SIZE:
862 {
863 /* @todo make configurable. */
864 pConf32->u32Value = _1M;
865 } break;
866
867 default:
868 LogRel(("VBoxVideo: CONF32 %d not supported!!! Skipping.\n", pConf32->u32Index));
869 }
870 }
871 else if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_END)
872 {
873 if (pHdr->u16Length != 0)
874 {
875 LogRel(("VBoxVideo: Guest adapter information %s invalid length %d!!!\n", "END", pHdr->u16Length));
876 break;
877 }
878
879 break;
880 }
881 else if (pHdr->u8Type != VBOX_VIDEO_INFO_TYPE_NV_HEAP)
882 {
883 /** @todo why is Additions/WINNT/Graphics/Miniport/VBoxVideo. cpp pushing this to us? */
884 LogRel(("Guest adapter information contains unsupported type %d. The block has been skipped.\n", pHdr->u8Type));
885 }
886
887 pu8 += pHdr->u16Length;
888 }
889 }
890#endif /* !VBOX_WITH_HGSMI */
891}
892
893void Display::processDisplayData(void *pvVRAM, unsigned uScreenId)
894{
895 if (uScreenId >= mcMonitors)
896 {
897 LogRel(("VBoxVideo: Guest display information invalid display index %d!!!\n", uScreenId));
898 return;
899 }
900
901 /* Get the display information structure. */
902 DISPLAYFBINFO *pFBInfo = &maFramebuffers[uScreenId];
903
904 uint8_t *pu8 = (uint8_t *)pvVRAM;
905 pu8 += pFBInfo->u32Offset + pFBInfo->u32MaxFramebufferSize;
906
907 // @todo
908 uint8_t *pu8End = pu8 + pFBInfo->u32InformationSize;
909
910 VBOXVIDEOINFOHDR *pHdr;
911
912 for (;;)
913 {
914 pHdr = (VBOXVIDEOINFOHDR *)pu8;
915 pu8 += sizeof(VBOXVIDEOINFOHDR);
916
917 if (pu8 >= pu8End)
918 {
919 LogRel(("VBoxVideo: Guest display information overflow!!!\n"));
920 break;
921 }
922
923 if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_SCREEN)
924 {
925 if (pHdr->u16Length != sizeof(VBOXVIDEOINFOSCREEN))
926 {
927 LogRel(("VBoxVideo: Guest display information %s invalid length %d!!!\n", "SCREEN", pHdr->u16Length));
928 break;
929 }
930
931 VBOXVIDEOINFOSCREEN *pScreen = (VBOXVIDEOINFOSCREEN *)pu8;
932
933 pFBInfo->xOrigin = pScreen->xOrigin;
934 pFBInfo->yOrigin = pScreen->yOrigin;
935
936 pFBInfo->w = pScreen->u16Width;
937 pFBInfo->h = pScreen->u16Height;
938
939 LogRelFlow(("VBOX_VIDEO_INFO_TYPE_SCREEN: (%p) %d: at %d,%d, linesize 0x%X, size %dx%d, bpp %d, flags 0x%02X\n",
940 pHdr, uScreenId, pScreen->xOrigin, pScreen->yOrigin, pScreen->u32LineSize, pScreen->u16Width,
941 pScreen->u16Height, pScreen->bitsPerPixel, pScreen->u8Flags));
942
943 if (uScreenId != VBOX_VIDEO_PRIMARY_SCREEN)
944 {
945 /* Primary screen resize is eeeeeeeee by the VGA device. */
946 if (pFBInfo->fDisabled)
947 {
948 pFBInfo->fDisabled = false;
949 fireGuestMonitorChangedEvent(mParent->i_getEventSource(),
950 GuestMonitorChangedEventType_Enabled,
951 uScreenId,
952 pFBInfo->xOrigin, pFBInfo->yOrigin,
953 pFBInfo->w, pFBInfo->h);
954 }
955
956 i_handleDisplayResize(uScreenId, pScreen->bitsPerPixel,
957 (uint8_t *)pvVRAM + pFBInfo->u32Offset,
958 pScreen->u32LineSize,
959 pScreen->u16Width, pScreen->u16Height,
960 VBVA_SCREEN_F_ACTIVE);
961 }
962 }
963 else if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_END)
964 {
965 if (pHdr->u16Length != 0)
966 {
967 LogRel(("VBoxVideo: Guest adapter information %s invalid length %d!!!\n", "END", pHdr->u16Length));
968 break;
969 }
970
971 break;
972 }
973 else if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_HOST_EVENTS)
974 {
975 if (pHdr->u16Length != sizeof(VBOXVIDEOINFOHOSTEVENTS))
976 {
977 LogRel(("VBoxVideo: Guest display information %s invalid length %d!!!\n", "HOST_EVENTS", pHdr->u16Length));
978 break;
979 }
980
981 VBOXVIDEOINFOHOSTEVENTS *pHostEvents = (VBOXVIDEOINFOHOSTEVENTS *)pu8;
982
983 pFBInfo->pHostEvents = pHostEvents;
984
985 LogFlow(("VBOX_VIDEO_INFO_TYPE_HOSTEVENTS: (%p)\n",
986 pHostEvents));
987 }
988 else if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_LINK)
989 {
990 if (pHdr->u16Length != sizeof(VBOXVIDEOINFOLINK))
991 {
992 LogRel(("VBoxVideo: Guest adapter information %s invalid length %d!!!\n", "LINK", pHdr->u16Length));
993 break;
994 }
995
996 VBOXVIDEOINFOLINK *pLink = (VBOXVIDEOINFOLINK *)pu8;
997 pu8 += pLink->i32Offset;
998 }
999 else
1000 {
1001 LogRel(("Guest display information contains unsupported type %d\n", pHdr->u8Type));
1002 }
1003
1004 pu8 += pHdr->u16Length;
1005 }
1006}
1007
1008/* vi: set tabstop=4 shiftwidth=4 expandtab: */
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