VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Display/vbox.c@ 22274

Last change on this file since 22274 was 22274, checked in by vboxsync, 15 years ago

HGSMI saved state impl (not debugged yet)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.1 KB
Line 
1/* $Id: vbox.c 22274 2009-08-15 20:44:22Z vboxsync $ */
2/** @file
3 * Display - VirtualBox Win 2000/XP guest display driver, support functions.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22#include "driver.h"
23
24#include <VBox/VMMDev.h>
25#include <VBox/VBoxGuest.h>
26#include <VBox/err.h>
27#include <iprt/asm.h>
28
29/*
30 * There is a hardware ring buffer in the VBox VMMDev PCI memory space.
31 * All graphics commands go there serialized by vboxHwBufferBeginUpdate.
32 * and vboxHwBufferEndUpdate.
33 *
34 * off32Free is writing position. off32Data is reading position.
35 * off32Free == off32Data means buffer is empty.
36 * There must be always gap between off32Data and off32Free when data
37 * are in the buffer.
38 * Guest only changes off32Free, host changes off32Data.
39 */
40
41/* Forward declarations of internal functions. */
42static void vboxHwBufferFlush (PPDEV ppdev);
43static void vboxHwBufferPlaceDataAt (PPDEV ppdev, void *p, uint32_t cb, uint32_t offset);
44static BOOL vboxHwBufferWrite (PPDEV ppdev, const void *p, uint32_t cb);
45
46#ifndef VBOX_WITH_HGSMI
47/*
48 * Public hardware buffer methods.
49 */
50BOOL vboxVbvaEnable (PPDEV ppdev)
51{
52 BOOL bRc = FALSE;
53
54 ULONG returnedDataLength;
55 ULONG ulEnable = TRUE;
56
57 DISPDBG((1, "VBoxDisp::vboxVbvaEnable called\n"));
58
59 if (!ghsemHwBuffer)
60 {
61 return FALSE;
62 }
63
64 if (EngDeviceIoControl(ppdev->hDriver,
65 IOCTL_VIDEO_VBVA_ENABLE,
66 &ulEnable,
67 sizeof (ulEnable),
68 &ppdev->vbva,
69 sizeof (ppdev->vbva),
70 &returnedDataLength) == 0)
71 {
72 DISPDBG((1, "VBoxDisp::vboxVbvaEnable: vbva: pVbvaMemory = %p, pfnFlush = %p, pvFlush = %p.\n",
73 ppdev->vbva.pVbvaMemory, ppdev->vbva.pfnFlush, ppdev->vbva.pvFlush));
74
75 if (ppdev->vbva.pVbvaMemory
76 && ppdev->vbva.pfnFlush
77 && ppdev->vbva.pvFlush)
78 {
79 ppdev->fHwBufferOverflow = FALSE;
80 ppdev->pRecord = NULL;
81
82 /* All have been initialized. */
83 bRc = TRUE;
84 }
85 }
86
87 if (!bRc)
88 {
89 vboxVbvaDisable (ppdev);
90 }
91
92 return bRc;
93}
94
95void vboxVbvaDisable (PPDEV ppdev)
96{
97 DISPDBG((1, "VBoxDisp::vbvaDisable called.\n"));
98
99 RtlZeroMemory (&ppdev->vbva, sizeof (ppdev->vbva));
100
101 ppdev->fHwBufferOverflow = FALSE;
102 ppdev->pRecord = NULL;
103
104 return;
105}
106
107BOOL vboxHwBufferBeginUpdate (PPDEV ppdev)
108{
109 BOOL bRc = FALSE;
110
111 VBVAMEMORY *pVbvaMemory = ppdev->vbva.pVbvaMemory;
112
113 DISPDBG((1, "VBoxDisp::vboxHwBufferBeginUpdate called flags = 0x%08X\n", pVbvaMemory? pVbvaMemory->fu32ModeFlags: -1));
114
115 if ( pVbvaMemory
116 && (pVbvaMemory->fu32ModeFlags & VBVA_F_MODE_ENABLED))
117 {
118 uint32_t indexRecordNext;
119
120 EngAcquireSemaphore (ghsemHwBuffer);
121
122 VBVA_ASSERT (!ppdev->fHwBufferOverflow);
123 VBVA_ASSERT (ppdev->pRecord == NULL);
124
125 indexRecordNext = (pVbvaMemory->indexRecordFree + 1) % VBVA_MAX_RECORDS;
126
127 if (indexRecordNext == pVbvaMemory->indexRecordFirst)
128 {
129 /* All slots in the records queue are used. */
130 vboxHwBufferFlush (ppdev);
131 }
132
133 if (indexRecordNext == pVbvaMemory->indexRecordFirst)
134 {
135 /* Even after flush there is no place. Fail the request. */
136 DISPDBG((1, "VBoxDisp::vboxHwBufferBeginUpdate no space in the queue of records!!! first %d, last %d\n",
137 pVbvaMemory->indexRecordFirst, pVbvaMemory->indexRecordFree));
138 EngReleaseSemaphore (ghsemHwBuffer);
139 }
140 else
141 {
142 /* Initialize the record. */
143 VBVARECORD *pRecord = &pVbvaMemory->aRecords[pVbvaMemory->indexRecordFree];
144
145 pRecord->cbRecord = VBVA_F_RECORD_PARTIAL;
146
147 pVbvaMemory->indexRecordFree = indexRecordNext;
148
149 DISPDBG((1, "VBoxDisp::vboxHwBufferBeginUpdate indexRecordNext = %d\n", indexRecordNext));
150
151 /* Remember which record we are using. */
152 ppdev->pRecord = pRecord;
153
154 bRc = TRUE;
155 }
156 }
157
158 return bRc;
159}
160
161void vboxHwBufferEndUpdate (PPDEV ppdev)
162{
163 VBVAMEMORY *pVbvaMemory;
164 VBVARECORD *pRecord;
165
166 DISPDBG((1, "VBoxDisp::vboxHwBufferEndUpdate called\n"));
167
168 pVbvaMemory = ppdev->vbva.pVbvaMemory;
169 VBVA_ASSERT(pVbvaMemory);
170
171 pRecord = ppdev->pRecord;
172 VBVA_ASSERT (pRecord && (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL));
173
174 /* Mark the record completed. */
175 pRecord->cbRecord &= ~VBVA_F_RECORD_PARTIAL;
176
177 ppdev->fHwBufferOverflow = FALSE;
178 ppdev->pRecord = NULL;
179
180 EngReleaseSemaphore (ghsemHwBuffer);
181
182 return;
183}
184
185/*
186 * Private operations.
187 */
188static uint32_t vboxHwBufferAvail (VBVAMEMORY *pVbvaMemory)
189{
190 int32_t i32Diff = pVbvaMemory->off32Data - pVbvaMemory->off32Free;
191
192 return i32Diff > 0? i32Diff: VBVA_RING_BUFFER_SIZE + i32Diff;
193}
194
195static void vboxHwBufferFlush (PPDEV ppdev)
196{
197 VBVAMEMORY *pVbvaMemory = ppdev->vbva.pVbvaMemory;
198
199 VBVA_ASSERT (pVbvaMemory);
200
201 ppdev->vbva.pfnFlush (ppdev->vbva.pvFlush);
202
203 return;
204}
205
206static void vboxHwBufferPlaceDataAt (PPDEV ppdev, void *p, uint32_t cb, uint32_t offset)
207{
208 VBVAMEMORY *pVbvaMemory = ppdev->vbva.pVbvaMemory;
209
210 uint32_t u32BytesTillBoundary = VBVA_RING_BUFFER_SIZE - offset;
211 uint8_t *dst = &pVbvaMemory->au8RingBuffer[offset];
212 int32_t i32Diff = cb - u32BytesTillBoundary;
213
214 if (i32Diff <= 0)
215 {
216 /* Chunk will not cross buffer boundary. */
217 memcpy (dst, p, cb);
218 }
219 else
220 {
221 /* Chunk crosses buffer boundary. */
222 memcpy (dst, p, u32BytesTillBoundary);
223 memcpy (&pVbvaMemory->au8RingBuffer[0], (uint8_t *)p + u32BytesTillBoundary, i32Diff);
224 }
225
226 return;
227}
228
229static BOOL vboxHwBufferWrite (PPDEV ppdev, const void *p, uint32_t cb)
230{
231 VBVAMEMORY *pVbvaMemory;
232 VBVARECORD *pRecord;
233 uint32_t cbHwBufferAvail;
234
235 uint32_t cbWritten = 0;
236
237 VBVA_ASSERT(ppdev);
238
239 if (ppdev->fHwBufferOverflow)
240 {
241 return FALSE;
242 }
243
244 pVbvaMemory = ppdev->vbva.pVbvaMemory;
245 VBVA_ASSERT (pVbvaMemory->indexRecordFirst != pVbvaMemory->indexRecordFree);
246
247 pRecord = ppdev->pRecord;
248 VBVA_ASSERT (pRecord && (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL));
249
250 DISPDBG((1, "VW %d\n", cb));
251
252 cbHwBufferAvail = vboxHwBufferAvail (pVbvaMemory);
253
254 while (cb > 0)
255 {
256 uint32_t cbChunk = cb;
257
258// DISPDBG((1, "VBoxDisp::vboxHwBufferWrite pVbvaMemory->off32Free %d, pRecord->cbRecord 0x%08X, cbHwBufferAvail %d, cb %d, cbWritten %d\n", pVbvaMemory->off32Free, pRecord->cbRecord, cbHwBufferAvail, cb, cbWritten));
259
260 if (cbChunk >= cbHwBufferAvail)
261 {
262 DISPDBG((1, "VBoxDisp::vboxHwBufferWrite 1) avail %d, chunk %d\n", cbHwBufferAvail, cbChunk));
263
264 vboxHwBufferFlush (ppdev);
265
266 cbHwBufferAvail = vboxHwBufferAvail (pVbvaMemory);
267
268 if (cbChunk >= cbHwBufferAvail)
269 {
270 DISPDBG((1, "VBoxDisp::vboxHwBufferWrite: no place for %d bytes. Only %d bytes available after flush. Going to partial writes.\n", cb, cbHwBufferAvail));
271
272 if (cbHwBufferAvail <= VBVA_RING_BUFFER_THRESHOLD)
273 {
274 DISPDBG((1, "VBoxDisp::vboxHwBufferWrite: Buffer overflow!!!\n"));
275 ppdev->fHwBufferOverflow = TRUE;
276 VBVA_ASSERT(FALSE);
277 return FALSE;
278 }
279
280 cbChunk = cbHwBufferAvail - VBVA_RING_BUFFER_THRESHOLD;
281 }
282 }
283
284 VBVA_ASSERT(cbChunk <= cb);
285 VBVA_ASSERT(cbChunk <= vboxHwBufferAvail (pVbvaMemory));
286
287 vboxHwBufferPlaceDataAt (ppdev, (uint8_t *)p + cbWritten, cbChunk, pVbvaMemory->off32Free);
288
289 pVbvaMemory->off32Free = (pVbvaMemory->off32Free + cbChunk) % VBVA_RING_BUFFER_SIZE;
290 pRecord->cbRecord += cbChunk;
291 cbHwBufferAvail -= cbChunk;
292
293 cb -= cbChunk;
294 cbWritten += cbChunk;
295 }
296
297 return TRUE;
298}
299
300/*
301 * Public writer to hardware buffer.
302 */
303BOOL vboxWrite (PPDEV ppdev, const void *pv, uint32_t cb)
304{
305 return vboxHwBufferWrite (ppdev, pv, cb);
306}
307
308BOOL vboxOrderSupported (PPDEV ppdev, unsigned code)
309{
310 VBVAMEMORY *pVbvaMemory;
311
312 pVbvaMemory = ppdev->vbva.pVbvaMemory;
313
314 if (pVbvaMemory->fu32ModeFlags & VBVA_F_MODE_VRDP_ORDER_MASK)
315 {
316 /* Order masking enabled. */
317 if (pVbvaMemory->fu32SupportedOrders & (1 << code))
318 {
319 return TRUE;
320 }
321 }
322
323 return FALSE;
324}
325
326void VBoxProcessDisplayInfo(PPDEV ppdev)
327{
328 DWORD returnedDataLength;
329
330 DISPDBG((1, "Process: %d,%d\n", ppdev->ptlDevOrg.x, ppdev->ptlDevOrg.y));
331
332 EngDeviceIoControl(ppdev->hDriver,
333 IOCTL_VIDEO_INTERPRET_DISPLAY_MEMORY,
334 NULL,
335 0,
336 NULL,
337 0,
338 &returnedDataLength);
339}
340
341#else /* VBOX_WITH_HGSMI */
342
343static void vboxHGSMIBufferSubmit (PPDEV ppdev, void *p)
344{
345 HGSMIOFFSET offBuffer = HGSMIHeapBufferOffset (&ppdev->hgsmiDisplayHeap, p);
346
347 ppdev->pfnHGSMIGHCommandPost(ppdev->hMpHGSMI, offBuffer);
348// ASMOutU16 (VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VBVA_GUEST);
349// ASMOutU32 (VBE_DISPI_IOPORT_DATA, offBuffer);
350}
351
352static BOOL vboxVBVAInformHost (PPDEV ppdev, BOOL bEnable)
353{
354 BOOL bRc = FALSE;
355
356 if (ppdev->bHGSMISupported)
357 {
358 void *p = HGSMIHeapAlloc (&ppdev->hgsmiDisplayHeap,
359 sizeof (VBVAENABLE),
360 HGSMI_CH_VBVA,
361 VBVA_ENABLE);
362 if (!p)
363 {
364 DISPDBG((0, "VBoxDISP::vboxVBVAInformHost: HGSMIHeapAlloc failed\n"));
365 }
366 else
367 {
368 VBVAENABLE *pEnable = (VBVAENABLE *)p;
369
370 pEnable->u32Flags = bEnable? VBVA_F_ENABLE: VBVA_F_DISABLE;
371 pEnable->u32Offset = ppdev->layout.offVBVABuffer;
372
373 vboxHGSMIBufferSubmit (ppdev, p);
374
375 HGSMIHeapFree (&ppdev->hgsmiDisplayHeap, p);
376
377 bRc = TRUE;
378 }
379 }
380
381 return bRc;
382}
383
384/*
385 * Public hardware buffer methods.
386 */
387BOOL vboxVbvaEnable (PPDEV ppdev)
388{
389 BOOL bRc = FALSE;
390
391 DISPDBG((1, "VBoxDisp::vboxVbvaEnable called\n"));
392
393 if (ppdev->bHGSMISupported)
394 {
395 VBVABUFFER *pVBVA = (VBVABUFFER *)((uint8_t *)ppdev->pjScreen + ppdev->layout.offVBVABuffer);
396
397 pVBVA->u32HostEvents = 0;
398 pVBVA->u32SupportedOrders = 0;
399 pVBVA->off32Data = 0;
400 pVBVA->off32Free = 0;
401 RtlZeroMemory (pVBVA->aRecords, sizeof (pVBVA->aRecords));
402 pVBVA->indexRecordFirst = 0;
403 pVBVA->indexRecordFree = 0;
404 pVBVA->cbPartialWriteThreshold = 256;
405 pVBVA->cbData = ppdev->layout.cbVBVABuffer - sizeof (VBVABUFFER) + sizeof (pVBVA->au8Data);
406
407 ppdev->fHwBufferOverflow = FALSE;
408 ppdev->pRecord = NULL;
409 ppdev->pVBVA = pVBVA;
410
411 bRc = vboxVBVAInformHost (ppdev, TRUE);
412 }
413
414 if (!bRc)
415 {
416 vboxVbvaDisable (ppdev);
417 }
418
419 return bRc;
420}
421
422void vboxVbvaDisable (PPDEV ppdev)
423{
424 DISPDBG((1, "VBoxDisp::vbvaDisable called.\n"));
425
426 ppdev->fHwBufferOverflow = FALSE;
427 ppdev->pRecord = NULL;
428 ppdev->pVBVA = NULL;
429
430 vboxVBVAInformHost (ppdev, FALSE);
431
432 return;
433}
434
435BOOL vboxHwBufferBeginUpdate (PPDEV ppdev)
436{
437 BOOL bRc = FALSE;
438
439 // DISPDBG((1, "VBoxDisp::vboxHwBufferBeginUpdate called flags = 0x%08X\n",
440 // ppdev->pVBVA? ppdev->pVBVA->u32HostEvents: -1));
441
442 if ( ppdev->pVBVA
443 && (ppdev->pVBVA->u32HostEvents & VBVA_F_MODE_ENABLED))
444 {
445 uint32_t indexRecordNext;
446
447 VBVA_ASSERT (!ppdev->fHwBufferOverflow);
448 VBVA_ASSERT (ppdev->pRecord == NULL);
449
450 indexRecordNext = (ppdev->pVBVA->indexRecordFree + 1) % VBVA_MAX_RECORDS;
451
452 if (indexRecordNext == ppdev->pVBVA->indexRecordFirst)
453 {
454 /* All slots in the records queue are used. */
455 vboxHwBufferFlush (ppdev);
456 }
457
458 if (indexRecordNext == ppdev->pVBVA->indexRecordFirst)
459 {
460 /* Even after flush there is no place. Fail the request. */
461 DISPDBG((1, "VBoxDisp::vboxHwBufferBeginUpdate no space in the queue of records!!! first %d, last %d\n",
462 ppdev->pVBVA->indexRecordFirst, ppdev->pVBVA->indexRecordFree));
463 }
464 else
465 {
466 /* Initialize the record. */
467 VBVARECORD *pRecord = &ppdev->pVBVA->aRecords[ppdev->pVBVA->indexRecordFree];
468
469 pRecord->cbRecord = VBVA_F_RECORD_PARTIAL;
470
471 ppdev->pVBVA->indexRecordFree = indexRecordNext;
472
473 // DISPDBG((1, "VBoxDisp::vboxHwBufferBeginUpdate indexRecordNext = %d\n", indexRecordNext));
474
475 /* Remember which record we are using. */
476 ppdev->pRecord = pRecord;
477
478 bRc = TRUE;
479 }
480 }
481
482 return bRc;
483}
484
485void vboxHwBufferEndUpdate (PPDEV ppdev)
486{
487 VBVARECORD *pRecord;
488
489 // DISPDBG((1, "VBoxDisp::vboxHwBufferEndUpdate called\n"));
490
491 VBVA_ASSERT(ppdev->pVBVA);
492
493 pRecord = ppdev->pRecord;
494 VBVA_ASSERT (pRecord && (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL));
495
496 /* Mark the record completed. */
497 pRecord->cbRecord &= ~VBVA_F_RECORD_PARTIAL;
498
499 ppdev->fHwBufferOverflow = FALSE;
500 ppdev->pRecord = NULL;
501
502 return;
503}
504
505/*
506 * Private operations.
507 */
508static uint32_t vboxHwBufferAvail (const VBVABUFFER *pVBVA)
509{
510 int32_t i32Diff = pVBVA->off32Data - pVBVA->off32Free;
511
512 return i32Diff > 0? i32Diff: pVBVA->cbData + i32Diff;
513}
514
515static void vboxHwBufferFlush (PPDEV ppdev)
516{
517 /* Issue the flush command. */
518 void *p = HGSMIHeapAlloc (&ppdev->hgsmiDisplayHeap,
519 sizeof (VBVA_FLUSH),
520 HGSMI_CH_VBVA,
521 VBVA_FLUSH);
522 if (!p)
523 {
524 DISPDBG((0, "VBoxDISP::vboxHwBufferFlush: HGSMIHeapAlloc failed\n"));
525 }
526 else
527 {
528 VBVAFLUSH *pFlush = (VBVAFLUSH *)p;
529
530 pFlush->u32Reserved = 0;
531
532 vboxHGSMIBufferSubmit (ppdev, p);
533
534 HGSMIHeapFree (&ppdev->hgsmiDisplayHeap, p);
535 }
536
537 return;
538}
539
540static void vboxHwBufferPlaceDataAt (PPDEV ppdev, const void *p, uint32_t cb, uint32_t offset)
541{
542 VBVABUFFER *pVBVA = ppdev->pVBVA;
543 uint32_t u32BytesTillBoundary = pVBVA->cbData - offset;
544 uint8_t *dst = &pVBVA->au8Data[offset];
545 int32_t i32Diff = cb - u32BytesTillBoundary;
546
547 if (i32Diff <= 0)
548 {
549 /* Chunk will not cross buffer boundary. */
550 memcpy (dst, p, cb);
551 }
552 else
553 {
554 /* Chunk crosses buffer boundary. */
555 memcpy (dst, p, u32BytesTillBoundary);
556 memcpy (&pVBVA->au8Data[0], (uint8_t *)p + u32BytesTillBoundary, i32Diff);
557 }
558
559 return;
560}
561
562static BOOL vboxHwBufferWrite (PPDEV ppdev, const void *p, uint32_t cb)
563{
564 VBVARECORD *pRecord;
565 uint32_t cbHwBufferAvail;
566
567 uint32_t cbWritten = 0;
568
569 VBVABUFFER *pVBVA = ppdev->pVBVA;
570 VBVA_ASSERT(pVBVA);
571
572 if (!pVBVA || ppdev->fHwBufferOverflow)
573 {
574 return FALSE;
575 }
576
577 VBVA_ASSERT (pVBVA->indexRecordFirst != pVBVA->indexRecordFree);
578
579 pRecord = ppdev->pRecord;
580 VBVA_ASSERT (pRecord && (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL));
581
582 DISPDBG((1, "VW %d\n", cb));
583
584 cbHwBufferAvail = vboxHwBufferAvail (pVBVA);
585
586 while (cb > 0)
587 {
588 uint32_t cbChunk = cb;
589
590 // DISPDBG((1, "VBoxDisp::vboxHwBufferWrite pVBVA->off32Free %d, pRecord->cbRecord 0x%08X, cbHwBufferAvail %d, cb %d, cbWritten %d\n",
591 // pVBVA->off32Free, pRecord->cbRecord, cbHwBufferAvail, cb, cbWritten));
592
593 if (cbChunk >= cbHwBufferAvail)
594 {
595 DISPDBG((1, "VBoxDisp::vboxHwBufferWrite 1) avail %d, chunk %d\n", cbHwBufferAvail, cbChunk));
596
597 vboxHwBufferFlush (ppdev);
598
599 cbHwBufferAvail = vboxHwBufferAvail (pVBVA);
600
601 if (cbChunk >= cbHwBufferAvail)
602 {
603 DISPDBG((1, "VBoxDisp::vboxHwBufferWrite: no place for %d bytes. Only %d bytes available after flush. Going to partial writes.\n",
604 cb, cbHwBufferAvail));
605
606 if (cbHwBufferAvail <= pVBVA->cbPartialWriteThreshold)
607 {
608 DISPDBG((1, "VBoxDisp::vboxHwBufferWrite: Buffer overflow!!!\n"));
609 ppdev->fHwBufferOverflow = TRUE;
610 VBVA_ASSERT(FALSE);
611 return FALSE;
612 }
613
614 cbChunk = cbHwBufferAvail - pVBVA->cbPartialWriteThreshold;
615 }
616 }
617
618 VBVA_ASSERT(cbChunk <= cb);
619 VBVA_ASSERT(cbChunk <= vboxHwBufferAvail (pVBVA));
620
621 vboxHwBufferPlaceDataAt (ppdev, (uint8_t *)p + cbWritten, cbChunk, pVBVA->off32Free);
622
623 pVBVA->off32Free = (pVBVA->off32Free + cbChunk) % pVBVA->cbData;
624 pRecord->cbRecord += cbChunk;
625 cbHwBufferAvail -= cbChunk;
626
627 cb -= cbChunk;
628 cbWritten += cbChunk;
629 }
630
631 return TRUE;
632}
633
634/*
635 * Public writer to the hardware buffer.
636 */
637BOOL vboxWrite (PPDEV ppdev, const void *pv, uint32_t cb)
638{
639 return vboxHwBufferWrite (ppdev, pv, cb);
640}
641
642BOOL vboxOrderSupported (PPDEV ppdev, unsigned code)
643{
644 VBVABUFFER *pVBVA = ppdev->pVBVA;
645
646 if (!pVBVA)
647 {
648 return FALSE;
649 }
650
651 if (pVBVA->u32SupportedOrders & (1 << code))
652 {
653 return TRUE;
654 }
655
656 return FALSE;
657}
658
659void VBoxProcessDisplayInfo (PPDEV ppdev)
660{
661 if (ppdev->bHGSMISupported)
662 {
663 /* Issue the screen info command. */
664 void *p = HGSMIHeapAlloc (&ppdev->hgsmiDisplayHeap,
665 sizeof (VBVAINFOSCREEN),
666 HGSMI_CH_VBVA,
667 VBVA_INFO_SCREEN);
668 if (!p)
669 {
670 DISPDBG((0, "VBoxDISP::vboxHwBufferFlush: HGSMIHeapAlloc failed\n"));
671 }
672 else
673 {
674 VBVAINFOSCREEN *pScreen = (VBVAINFOSCREEN *)p;
675
676 pScreen->u32ViewIndex = ppdev->iDevice;
677 pScreen->i32OriginX = ppdev->ptlDevOrg.x;
678 pScreen->i32OriginY = ppdev->ptlDevOrg.y;
679 pScreen->u32LineSize = ppdev->lDeltaScreen > 0?ppdev->lDeltaScreen: -ppdev->lDeltaScreen;
680 pScreen->u32Width = ppdev->cxScreen;
681 pScreen->u32Height = ppdev->cyScreen;
682 pScreen->u16BitsPerPixel = (uint16_t)ppdev->ulBitCount;
683 pScreen->u16Flags = VBVA_SCREEN_F_ACTIVE;
684
685 vboxHGSMIBufferSubmit (ppdev, p);
686
687 HGSMIHeapFree (&ppdev->hgsmiDisplayHeap, p);
688 }
689 }
690
691 return;
692}
693
694# ifdef VBOX_WITH_VIDEOHWACCEL
695
696VBOXVHWACMD* vboxVHWACommandCreate (PPDEV ppdev, VBOXVHWACMD_TYPE enmCmd, VBOXVHWACMD_LENGTH cbCmd)
697{
698 VBOXVHWACMD* pHdr = (VBOXVHWACMD*)HGSMIHeapAlloc (&ppdev->hgsmiDisplayHeap,
699 cbCmd + VBOXVHWACMD_HEADSIZE(),
700 HGSMI_CH_VBVA,
701 VBVA_VHWA_CMD);
702 if (!pHdr)
703 {
704 DISPDBG((0, "VBoxDISP::vboxVHWACommandCreate: HGSMIHeapAlloc failed\n"));
705 }
706 else
707 {
708 memset(pHdr, 0, sizeof(VBOXVHWACMD));
709 pHdr->iDisplay = ppdev->iDevice;
710 pHdr->rc = VERR_GENERAL_FAILURE;
711 pHdr->enmCmd = enmCmd;
712 }
713
714 /* temporary hack */
715 vboxVHWACommandCheckHostCmds(ppdev);
716
717 return pHdr;
718}
719
720void vboxVHWACommandFree (PPDEV ppdev, VBOXVHWACMD* pCmd)
721{
722 HGSMIHeapFree (&ppdev->hgsmiDisplayHeap, pCmd);
723}
724
725static DECLCALLBACK(void) vboxVHWACommandCompletionCallbackEvent(PPDEV ppdev, VBOXVHWACMD * pCmd, void * pContext)
726{
727 PEVENT pEvent = (PEVENT)pContext;
728 LONG oldState = EngSetEvent(pEvent);
729 Assert(!oldState);
730}
731
732static int vboxVHWAHanldeVHWACmdCompletion(PPDEV ppdev, VBVAHOSTCMD * pHostCmd)
733{
734 VBVAHOSTCMDVHWACMDCOMPLETE * pComplete = VBVAHOSTCMD_BODY(pHostCmd, VBVAHOSTCMDVHWACMDCOMPLETE);
735 VBOXVHWACMD* pComplCmd = (VBOXVHWACMD*)HGSMIOffsetToPointer (&ppdev->hgsmiDisplayHeap.area, pComplete->offCmd);
736 PFNVBOXVHWACMDCOMPLETION pfnCompletion = (PFNVBOXVHWACMDCOMPLETION)pComplCmd->GuestVBVAReserved1;
737 void * pContext = (void *)pComplCmd->GuestVBVAReserved2;
738
739 pfnCompletion(ppdev, pComplCmd, pContext);
740
741 vboxVBVAHostCommandComplete(ppdev, pHostCmd);
742
743 return 0;
744}
745
746static void vboxVBVAHostCommandHanlder(PPDEV ppdev, VBVAHOSTCMD * pCmd)
747{
748 int rc = VINF_SUCCESS;
749 switch(pCmd->customOpCode)
750 {
751# ifdef VBOX_WITH_VIDEOHWACCEL
752 case VBVAHG_DCUSTOM_VHWA_CMDCOMPLETE:
753 {
754 vboxVHWAHanldeVHWACmdCompletion(ppdev, pCmd);
755 break;
756 }
757# endif
758 default:
759 {
760 Assert(0);
761 vboxVBVAHostCommandComplete(ppdev, pCmd);
762 }
763 }
764}
765
766void vboxVHWACommandCheckHostCmds(PPDEV ppdev)
767{
768 VBVAHOSTCMD * pCmd, * pNextCmd;
769 int rc = ppdev->pfnHGSMIRequestCommands(ppdev->hMpHGSMI, HGSMI_CH_VBVA, &pCmd);
770 Assert(RT_SUCCESS(rc));
771 if(RT_SUCCESS(rc))
772 {
773 for(;pCmd; pCmd = pNextCmd)
774 {
775 pNextCmd = pCmd->u.pNext;
776 vboxVBVAHostCommandHanlder(ppdev, pCmd);
777 }
778 }
779}
780
781void vboxVHWACommandSubmitAsynchByEvent (PPDEV ppdev, VBOXVHWACMD* pCmd, PEVENT pEvent)
782{
783// Assert(0);
784 pCmd->GuestVBVAReserved1 = (uintptr_t)pEvent;
785 pCmd->GuestVBVAReserved2 = 0;
786
787 /* complete it asynchronously by setting event */
788 pCmd->Flags |= VBOXVHWACMD_FLAG_GH_ASYNCH_EVENT;
789 vboxHGSMIBufferSubmit (ppdev, pCmd);
790 //TODO: dbg
791#if 0
792 if(!(ASMAtomicReadU32((volatile uint32_t *)&pCmd->Flags) & VBOXVHWACMD_FLAG_HG_ASYNCH))
793 {
794 /* the command is completed */
795 EngSetEvent(pEvent);
796 }
797#endif
798}
799
800BOOL vboxVHWACommandSubmit (PPDEV ppdev, VBOXVHWACMD* pCmd)
801{
802 PEVENT pEvent;
803 BOOL brc = EngCreateEvent(&pEvent);
804 Assert(brc);
805
806 if(brc)
807 {
808 pCmd->Flags |= VBOXVHWACMD_FLAG_GH_ASYNCH_IRQ;
809 vboxVHWACommandSubmitAsynchByEvent (ppdev, pCmd, pEvent);
810
811 brc = EngWaitForSingleObject(pEvent,
812 NULL /*IN PLARGE_INTEGER pTimeOut*/
813 );
814 Assert(brc);
815 if(brc)
816 {
817 EngDeleteEvent(pEvent);
818 }
819 }
820 return brc;
821}
822
823/* do not wait for completion */
824void vboxVHWACommandSubmitAsynch (PPDEV ppdev, VBOXVHWACMD* pCmd, PFNVBOXVHWACMDCOMPLETION pfnCompletion, void * pContext)
825{
826// Assert(0);
827 pCmd->GuestVBVAReserved1 = (uintptr_t)pfnCompletion;
828 pCmd->GuestVBVAReserved2 = (uintptr_t)pContext;
829
830 vboxHGSMIBufferSubmit (ppdev, pCmd);
831 //TODO: dbg
832#if 0
833 if(!(pCmd->Flags & VBOXVHWACMD_FLAG_HG_ASYNCH))
834 {
835 /* the command is completed */
836 pfnCompletion(ppdev, pCmd, pContext);
837 }
838#endif
839}
840
841static DECLCALLBACK(void) vboxVHWAFreeCmdCompletion(PPDEV ppdev, VBOXVHWACMD * pCmd, void * pContext)
842{
843 vboxVHWACommandFree(ppdev, pCmd);
844}
845
846void vboxVHWACommandSubmitAsynchAndComplete (PPDEV ppdev, VBOXVHWACMD* pCmd)
847{
848// Assert(0);
849 pCmd->GuestVBVAReserved1 = (uintptr_t)vboxVHWAFreeCmdCompletion;
850
851 pCmd->Flags |= VBOXVHWACMD_FLAG_GH_ASYNCH_NOCOMPLETION;
852
853 vboxHGSMIBufferSubmit (ppdev, pCmd);
854 //TODO: dbg
855#if 0
856 if(!(pCmd->Flags & VBOXVHWACMD_FLAG_HG_ASYNCH)
857 || pCmd->Flags & VBOXVHWACMD_FLAG_HG_ASYNCH_RETURNED)
858 {
859 /* the command is completed */
860 vboxVHWAFreeCmdCompletion(ppdev, pCmd, NULL);
861 }
862#endif
863}
864
865void vboxVHWAFreeHostInfo1(PPDEV ppdev, VBOXVHWACMD_QUERYINFO1* pInfo)
866{
867 VBOXVHWACMD* pCmd = VBOXVHWACMD_HEAD(pInfo);
868 vboxVHWACommandFree (ppdev, pCmd);
869}
870
871void vboxVHWAFreeHostInfo2(PPDEV ppdev, VBOXVHWACMD_QUERYINFO2* pInfo)
872{
873 VBOXVHWACMD* pCmd = VBOXVHWACMD_HEAD(pInfo);
874 vboxVHWACommandFree (ppdev, pCmd);
875}
876
877VBOXVHWACMD_QUERYINFO1* vboxVHWAQueryHostInfo1(PPDEV ppdev)
878{
879 VBOXVHWACMD* pCmd = vboxVHWACommandCreate (ppdev, VBOXVHWACMD_TYPE_QUERY_INFO1, sizeof(VBOXVHWACMD_QUERYINFO1));
880 VBOXVHWACMD_QUERYINFO1 *pInfo1;
881 if (!pCmd)
882 {
883 DISPDBG((0, "VBoxDISP::vboxVHWAQueryHostInfo1: vboxVHWACommandCreate failed\n"));
884 return NULL;
885 }
886
887 if (!pCmd)
888 {
889 DISPDBG((0, "VBoxDISP::vboxVHWAQueryHostInfo1: vboxVHWACommandCreate failed\n"));
890 return NULL;
891 }
892
893 pInfo1 = VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_QUERYINFO1);
894 pInfo1->u.in.guestVersion.maj = VBOXVHWA_VERSION_MAJ;
895 pInfo1->u.in.guestVersion.min = VBOXVHWA_VERSION_MIN;
896 pInfo1->u.in.guestVersion.bld = VBOXVHWA_VERSION_BLD;
897 pInfo1->u.in.guestVersion.reserved = VBOXVHWA_VERSION_RSV;
898
899 if(vboxVHWACommandSubmit (ppdev, pCmd))
900 {
901 if(RT_SUCCESS(pCmd->rc))
902 {
903 return VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_QUERYINFO1);
904 }
905 }
906
907 vboxVHWACommandFree (ppdev, pCmd);
908 return NULL;
909}
910
911VBOXVHWACMD_QUERYINFO2* vboxVHWAQueryHostInfo2(PPDEV ppdev, uint32_t numFourCC)
912{
913 VBOXVHWACMD* pCmd = vboxVHWACommandCreate (ppdev, VBOXVHWACMD_TYPE_QUERY_INFO2, VBOXVHWAINFO2_SIZE(numFourCC));
914 VBOXVHWACMD_QUERYINFO2 *pInfo2;
915 if (!pCmd)
916 {
917 DISPDBG((0, "VBoxDISP::vboxVHWAQueryHostInfo1: vboxVHWACommandCreate failed\n"));
918 return NULL;
919 }
920
921 pInfo2 = VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_QUERYINFO2);
922 pInfo2->numFourCC = numFourCC;
923
924 if(vboxVHWACommandSubmit (ppdev, pCmd))
925 {
926 if(RT_SUCCESS(pCmd->rc))
927 {
928 if(pInfo2->numFourCC == numFourCC)
929 {
930 return pInfo2;
931 }
932 }
933 }
934
935 vboxVHWACommandFree (ppdev, pCmd);
936 return NULL;
937}
938
939int vboxVHWAInitHostInfo1(PPDEV ppdev)
940{
941 VBOXVHWACMD_QUERYINFO1* pInfo = vboxVHWAQueryHostInfo1(ppdev);
942 if(!pInfo)
943 {
944 ppdev->vhwaInfo.bVHWAEnabled = false;
945 return VERR_OUT_OF_RESOURCES;
946 }
947
948 ppdev->vhwaInfo.caps = pInfo->u.out.caps;
949 ppdev->vhwaInfo.caps2 = pInfo->u.out.caps2;
950 ppdev->vhwaInfo.colorKeyCaps = pInfo->u.out.colorKeyCaps;
951 ppdev->vhwaInfo.stretchCaps = pInfo->u.out.stretchCaps;
952 ppdev->vhwaInfo.surfaceCaps = pInfo->u.out.surfaceCaps;
953 ppdev->vhwaInfo.numOverlays = pInfo->u.out.numOverlays;
954 ppdev->vhwaInfo.numFourCC = pInfo->u.out.numFourCC;
955 ppdev->vhwaInfo.bVHWAEnabled = (pInfo->u.out.cfgFlags & VBOXVHWA_CFG_ENABLED);
956 vboxVHWAFreeHostInfo1(ppdev, pInfo);
957 return VINF_SUCCESS;
958}
959
960int vboxVHWAInitHostInfo2(PPDEV ppdev, DWORD *pFourCC)
961{
962 VBOXVHWACMD_QUERYINFO2* pInfo = vboxVHWAQueryHostInfo2(ppdev, ppdev->vhwaInfo.numFourCC);
963 int rc = VINF_SUCCESS;
964
965 Assert(pInfo);
966 if(!pInfo)
967 return VERR_OUT_OF_RESOURCES;
968
969 if(ppdev->vhwaInfo.numFourCC)
970 {
971 memcpy(pFourCC, pInfo->FourCC, ppdev->vhwaInfo.numFourCC * sizeof(pFourCC[0]));
972 }
973 else
974 {
975 Assert(0);
976 rc = VERR_GENERAL_FAILURE;
977 }
978
979 vboxVHWAFreeHostInfo2(ppdev, pInfo);
980
981 return rc;
982}
983
984int vboxVHWAEnable(PPDEV ppdev)
985{
986 int rc = VERR_GENERAL_FAILURE;
987 VBOXVHWACMD* pCmd = vboxVHWACommandCreate (ppdev, VBOXVHWACMD_TYPE_ENABLE, 0);
988 if (!pCmd)
989 {
990 DISPDBG((0, "VBoxDISP::vboxVHWAQueryHostInfo1: vboxVHWACommandCreate failed\n"));
991 return rc;
992 }
993
994 if(vboxVHWACommandSubmit (ppdev, pCmd))
995 {
996 if(RT_SUCCESS(pCmd->rc))
997 {
998 rc = VINF_SUCCESS;
999 }
1000 }
1001
1002 vboxVHWACommandFree (ppdev, pCmd);
1003 return rc;
1004}
1005
1006int vboxVHWADisable(PPDEV ppdev)
1007{
1008 int rc = VERR_GENERAL_FAILURE;
1009 VBOXVHWACMD* pCmd = vboxVHWACommandCreate (ppdev, VBOXVHWACMD_TYPE_DISABLE, 0);
1010 if (!pCmd)
1011 {
1012 DISPDBG((0, "VBoxDISP::vboxVHWAQueryHostInfo1: vboxVHWACommandCreate failed\n"));
1013 return rc;
1014 }
1015
1016 if(vboxVHWACommandSubmit (ppdev, pCmd))
1017 {
1018 if(RT_SUCCESS(pCmd->rc))
1019 {
1020 rc = VINF_SUCCESS;
1021 }
1022 }
1023
1024 vboxVHWACommandFree (ppdev, pCmd);
1025
1026 vboxVHWACommandCheckHostCmds(ppdev);
1027
1028 return rc;
1029}
1030
1031# endif
1032
1033void vboxVBVAHostCommandComplete(PPDEV ppdev, VBVAHOSTCMD * pCmd)
1034{
1035 ppdev->pfnHGSMICommandComplete(ppdev->hMpHGSMI, pCmd);
1036}
1037
1038#endif /* VBOX_WITH_HGSMI */
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