VirtualBox

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

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

video hw accel: raise interrupts for urgent commands only, hgsmi host->guest synchronization fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.7 KB
Line 
1/* $Id: vbox.c 21609 2009-07-15 14:01:56Z 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 ASMOutU16 (VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VBVA_GUEST);
348 ASMOutU32 (VBE_DISPI_IOPORT_DATA, offBuffer);
349}
350
351static BOOL vboxVBVAInformHost (PPDEV ppdev, BOOL bEnable)
352{
353 BOOL bRc = FALSE;
354
355 if (ppdev->bHGSMISupported)
356 {
357 void *p = HGSMIHeapAlloc (&ppdev->hgsmiDisplayHeap,
358 sizeof (VBVAENABLE),
359 HGSMI_CH_VBVA,
360 VBVA_ENABLE);
361 if (!p)
362 {
363 DISPDBG((0, "VBoxDISP::vboxVBVAInformHost: HGSMIHeapAlloc failed\n"));
364 }
365 else
366 {
367 VBVAENABLE *pEnable = (VBVAENABLE *)p;
368
369 pEnable->u32Flags = bEnable? VBVA_F_ENABLE: VBVA_F_DISABLE;
370 pEnable->u32Offset = ppdev->layout.offVBVABuffer;
371
372 vboxHGSMIBufferSubmit (ppdev, p);
373
374 HGSMIHeapFree (&ppdev->hgsmiDisplayHeap, p);
375
376 bRc = TRUE;
377 }
378 }
379
380 return bRc;
381}
382
383/*
384 * Public hardware buffer methods.
385 */
386BOOL vboxVbvaEnable (PPDEV ppdev)
387{
388 BOOL bRc = FALSE;
389
390 DISPDBG((1, "VBoxDisp::vboxVbvaEnable called\n"));
391
392 if (ppdev->bHGSMISupported)
393 {
394 VBVABUFFER *pVBVA = (VBVABUFFER *)((uint8_t *)ppdev->pjScreen + ppdev->layout.offVBVABuffer);
395
396 pVBVA->u32HostEvents = 0;
397 pVBVA->u32SupportedOrders = 0;
398 pVBVA->off32Data = 0;
399 pVBVA->off32Free = 0;
400 RtlZeroMemory (pVBVA->aRecords, sizeof (pVBVA->aRecords));
401 pVBVA->indexRecordFirst = 0;
402 pVBVA->indexRecordFree = 0;
403 pVBVA->cbPartialWriteThreshold = 256;
404 pVBVA->cbData = ppdev->layout.cbVBVABuffer - sizeof (VBVABUFFER) + sizeof (pVBVA->au8Data);
405
406 ppdev->fHwBufferOverflow = FALSE;
407 ppdev->pRecord = NULL;
408 ppdev->pVBVA = pVBVA;
409
410 bRc = vboxVBVAInformHost (ppdev, TRUE);
411 }
412
413 if (!bRc)
414 {
415 vboxVbvaDisable (ppdev);
416 }
417
418 return bRc;
419}
420
421void vboxVbvaDisable (PPDEV ppdev)
422{
423 DISPDBG((1, "VBoxDisp::vbvaDisable called.\n"));
424
425 ppdev->fHwBufferOverflow = FALSE;
426 ppdev->pRecord = NULL;
427 ppdev->pVBVA = NULL;
428
429 vboxVBVAInformHost (ppdev, FALSE);
430
431 return;
432}
433
434BOOL vboxHwBufferBeginUpdate (PPDEV ppdev)
435{
436 BOOL bRc = FALSE;
437
438 // DISPDBG((1, "VBoxDisp::vboxHwBufferBeginUpdate called flags = 0x%08X\n",
439 // ppdev->pVBVA? ppdev->pVBVA->u32HostEvents: -1));
440
441 if ( ppdev->pVBVA
442 && (ppdev->pVBVA->u32HostEvents & VBVA_F_MODE_ENABLED))
443 {
444 uint32_t indexRecordNext;
445
446 VBVA_ASSERT (!ppdev->fHwBufferOverflow);
447 VBVA_ASSERT (ppdev->pRecord == NULL);
448
449 indexRecordNext = (ppdev->pVBVA->indexRecordFree + 1) % VBVA_MAX_RECORDS;
450
451 if (indexRecordNext == ppdev->pVBVA->indexRecordFirst)
452 {
453 /* All slots in the records queue are used. */
454 vboxHwBufferFlush (ppdev);
455 }
456
457 if (indexRecordNext == ppdev->pVBVA->indexRecordFirst)
458 {
459 /* Even after flush there is no place. Fail the request. */
460 DISPDBG((1, "VBoxDisp::vboxHwBufferBeginUpdate no space in the queue of records!!! first %d, last %d\n",
461 ppdev->pVBVA->indexRecordFirst, ppdev->pVBVA->indexRecordFree));
462 }
463 else
464 {
465 /* Initialize the record. */
466 VBVARECORD *pRecord = &ppdev->pVBVA->aRecords[ppdev->pVBVA->indexRecordFree];
467
468 pRecord->cbRecord = VBVA_F_RECORD_PARTIAL;
469
470 ppdev->pVBVA->indexRecordFree = indexRecordNext;
471
472 // DISPDBG((1, "VBoxDisp::vboxHwBufferBeginUpdate indexRecordNext = %d\n", indexRecordNext));
473
474 /* Remember which record we are using. */
475 ppdev->pRecord = pRecord;
476
477 bRc = TRUE;
478 }
479 }
480
481 return bRc;
482}
483
484void vboxHwBufferEndUpdate (PPDEV ppdev)
485{
486 VBVARECORD *pRecord;
487
488 // DISPDBG((1, "VBoxDisp::vboxHwBufferEndUpdate called\n"));
489
490 VBVA_ASSERT(ppdev->pVBVA);
491
492 pRecord = ppdev->pRecord;
493 VBVA_ASSERT (pRecord && (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL));
494
495 /* Mark the record completed. */
496 pRecord->cbRecord &= ~VBVA_F_RECORD_PARTIAL;
497
498 ppdev->fHwBufferOverflow = FALSE;
499 ppdev->pRecord = NULL;
500
501 return;
502}
503
504/*
505 * Private operations.
506 */
507static uint32_t vboxHwBufferAvail (const VBVABUFFER *pVBVA)
508{
509 int32_t i32Diff = pVBVA->off32Data - pVBVA->off32Free;
510
511 return i32Diff > 0? i32Diff: pVBVA->cbData + i32Diff;
512}
513
514static void vboxHwBufferFlush (PPDEV ppdev)
515{
516 /* Issue the flush command. */
517 void *p = HGSMIHeapAlloc (&ppdev->hgsmiDisplayHeap,
518 sizeof (VBVA_FLUSH),
519 HGSMI_CH_VBVA,
520 VBVA_FLUSH);
521 if (!p)
522 {
523 DISPDBG((0, "VBoxDISP::vboxHwBufferFlush: HGSMIHeapAlloc failed\n"));
524 }
525 else
526 {
527 VBVAFLUSH *pFlush = (VBVAFLUSH *)p;
528
529 pFlush->u32Reserved = 0;
530
531 vboxHGSMIBufferSubmit (ppdev, p);
532
533 HGSMIHeapFree (&ppdev->hgsmiDisplayHeap, p);
534 }
535
536 return;
537}
538
539static void vboxHwBufferPlaceDataAt (PPDEV ppdev, const void *p, uint32_t cb, uint32_t offset)
540{
541 VBVABUFFER *pVBVA = ppdev->pVBVA;
542 uint32_t u32BytesTillBoundary = pVBVA->cbData - offset;
543 uint8_t *dst = &pVBVA->au8Data[offset];
544 int32_t i32Diff = cb - u32BytesTillBoundary;
545
546 if (i32Diff <= 0)
547 {
548 /* Chunk will not cross buffer boundary. */
549 memcpy (dst, p, cb);
550 }
551 else
552 {
553 /* Chunk crosses buffer boundary. */
554 memcpy (dst, p, u32BytesTillBoundary);
555 memcpy (&pVBVA->au8Data[0], (uint8_t *)p + u32BytesTillBoundary, i32Diff);
556 }
557
558 return;
559}
560
561static BOOL vboxHwBufferWrite (PPDEV ppdev, const void *p, uint32_t cb)
562{
563 VBVARECORD *pRecord;
564 uint32_t cbHwBufferAvail;
565
566 uint32_t cbWritten = 0;
567
568 VBVABUFFER *pVBVA = ppdev->pVBVA;
569 VBVA_ASSERT(pVBVA);
570
571 if (!pVBVA || ppdev->fHwBufferOverflow)
572 {
573 return FALSE;
574 }
575
576 VBVA_ASSERT (pVBVA->indexRecordFirst != pVBVA->indexRecordFree);
577
578 pRecord = ppdev->pRecord;
579 VBVA_ASSERT (pRecord && (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL));
580
581 DISPDBG((1, "VW %d\n", cb));
582
583 cbHwBufferAvail = vboxHwBufferAvail (pVBVA);
584
585 while (cb > 0)
586 {
587 uint32_t cbChunk = cb;
588
589 // DISPDBG((1, "VBoxDisp::vboxHwBufferWrite pVBVA->off32Free %d, pRecord->cbRecord 0x%08X, cbHwBufferAvail %d, cb %d, cbWritten %d\n",
590 // pVBVA->off32Free, pRecord->cbRecord, cbHwBufferAvail, cb, cbWritten));
591
592 if (cbChunk >= cbHwBufferAvail)
593 {
594 DISPDBG((1, "VBoxDisp::vboxHwBufferWrite 1) avail %d, chunk %d\n", cbHwBufferAvail, cbChunk));
595
596 vboxHwBufferFlush (ppdev);
597
598 cbHwBufferAvail = vboxHwBufferAvail (pVBVA);
599
600 if (cbChunk >= cbHwBufferAvail)
601 {
602 DISPDBG((1, "VBoxDisp::vboxHwBufferWrite: no place for %d bytes. Only %d bytes available after flush. Going to partial writes.\n",
603 cb, cbHwBufferAvail));
604
605 if (cbHwBufferAvail <= pVBVA->cbPartialWriteThreshold)
606 {
607 DISPDBG((1, "VBoxDisp::vboxHwBufferWrite: Buffer overflow!!!\n"));
608 ppdev->fHwBufferOverflow = TRUE;
609 VBVA_ASSERT(FALSE);
610 return FALSE;
611 }
612
613 cbChunk = cbHwBufferAvail - pVBVA->cbPartialWriteThreshold;
614 }
615 }
616
617 VBVA_ASSERT(cbChunk <= cb);
618 VBVA_ASSERT(cbChunk <= vboxHwBufferAvail (pVBVA));
619
620 vboxHwBufferPlaceDataAt (ppdev, (uint8_t *)p + cbWritten, cbChunk, pVBVA->off32Free);
621
622 pVBVA->off32Free = (pVBVA->off32Free + cbChunk) % pVBVA->cbData;
623 pRecord->cbRecord += cbChunk;
624 cbHwBufferAvail -= cbChunk;
625
626 cb -= cbChunk;
627 cbWritten += cbChunk;
628 }
629
630 return TRUE;
631}
632
633/*
634 * Public writer to the hardware buffer.
635 */
636BOOL vboxWrite (PPDEV ppdev, const void *pv, uint32_t cb)
637{
638 return vboxHwBufferWrite (ppdev, pv, cb);
639}
640
641BOOL vboxOrderSupported (PPDEV ppdev, unsigned code)
642{
643 VBVABUFFER *pVBVA = ppdev->pVBVA;
644
645 if (!pVBVA)
646 {
647 return FALSE;
648 }
649
650 if (pVBVA->u32SupportedOrders & (1 << code))
651 {
652 return TRUE;
653 }
654
655 return FALSE;
656}
657
658void VBoxProcessDisplayInfo (PPDEV ppdev)
659{
660 if (ppdev->bHGSMISupported)
661 {
662 /* Issue the screen info command. */
663 void *p = HGSMIHeapAlloc (&ppdev->hgsmiDisplayHeap,
664 sizeof (VBVAINFOSCREEN),
665 HGSMI_CH_VBVA,
666 VBVA_INFO_SCREEN);
667 if (!p)
668 {
669 DISPDBG((0, "VBoxDISP::vboxHwBufferFlush: HGSMIHeapAlloc failed\n"));
670 }
671 else
672 {
673 VBVAINFOSCREEN *pScreen = (VBVAINFOSCREEN *)p;
674
675 pScreen->u32ViewIndex = ppdev->iDevice;
676 pScreen->i32OriginX = ppdev->ptlDevOrg.x;
677 pScreen->i32OriginY = ppdev->ptlDevOrg.y;
678 pScreen->u32LineSize = ppdev->lDeltaScreen > 0?ppdev->lDeltaScreen: -ppdev->lDeltaScreen;
679 pScreen->u32Width = ppdev->cxScreen;
680 pScreen->u32Height = ppdev->cyScreen;
681 pScreen->u16BitsPerPixel = (uint16_t)ppdev->ulBitCount;
682 pScreen->u16Flags = VBVA_SCREEN_F_ACTIVE;
683
684 vboxHGSMIBufferSubmit (ppdev, p);
685
686 HGSMIHeapFree (&ppdev->hgsmiDisplayHeap, p);
687 }
688 }
689
690 return;
691}
692
693# ifdef VBOX_WITH_VIDEOHWACCEL
694
695VBOXVHWACMD* vboxVHWACommandCreate (PPDEV ppdev, VBOXVHWACMD_TYPE enmCmd, VBOXVHWACMD_LENGTH cbCmd)
696{
697 VBOXVHWACMD* pHdr = (VBOXVHWACMD*)HGSMIHeapAlloc (&ppdev->hgsmiDisplayHeap,
698 cbCmd + VBOXVHWACMD_HEADSIZE(),
699 HGSMI_CH_VBVA,
700 VBVA_VHWA_CMD);
701 if (!pHdr)
702 {
703 DISPDBG((0, "VBoxDISP::vboxVHWACommandCreate: HGSMIHeapAlloc failed\n"));
704 }
705 else
706 {
707 memset(pHdr, 0, sizeof(VBOXVHWACMD));
708 pHdr->iDisplay = ppdev->iDevice;
709 pHdr->rc = VERR_GENERAL_FAILURE;
710 pHdr->enmCmd = enmCmd;
711 }
712
713 /* temporary hack */
714 vboxVHWACommandCheckHostCmds(ppdev);
715
716 return pHdr;
717}
718
719void vboxVHWACommandFree (PPDEV ppdev, VBOXVHWACMD* pCmd)
720{
721 HGSMIHeapFree (&ppdev->hgsmiDisplayHeap, pCmd);
722}
723
724static DECLCALLBACK(void) vboxVHWACommandCompletionCallbackEvent(PPDEV ppdev, VBOXVHWACMD * pCmd, void * pContext)
725{
726 PEVENT pEvent = (PEVENT)pContext;
727 LONG oldState = EngSetEvent(pEvent);
728 Assert(!oldState);
729}
730
731static int vboxVHWAHanldeVHWACmdCompletion(PPDEV ppdev, VBVAHOSTCMD * pHostCmd)
732{
733 VBVAHOSTCMDVHWACMDCOMPLETE * pComplete = VBVAHOSTCMD_BODY(pHostCmd, VBVAHOSTCMDVHWACMDCOMPLETE);
734 VBOXVHWACMD* pComplCmd = (VBOXVHWACMD*)HGSMIOffsetToPointer (&ppdev->hgsmiDisplayHeap.area, pComplete->offCmd);
735 PFNVBOXVHWACMDCOMPLETION pfnCompletion = (PFNVBOXVHWACMDCOMPLETION)pComplCmd->GuestVBVAReserved1;
736 void * pContext = (void *)pComplCmd->GuestVBVAReserved2;
737
738 pfnCompletion(ppdev, pComplCmd, pContext);
739
740 vboxVBVAHostCommandComplete(ppdev, pHostCmd);
741
742 return 0;
743}
744
745static void vboxVBVAHostCommandHanlder(PPDEV ppdev, VBVAHOSTCMD * pCmd)
746{
747 int rc = VINF_SUCCESS;
748 switch(pCmd->customOpCode)
749 {
750# ifdef VBOX_WITH_VIDEOHWACCEL
751 case VBVAHG_DCUSTOM_VHWA_CMDCOMPLETE:
752 {
753 vboxVHWAHanldeVHWACmdCompletion(ppdev, pCmd);
754 break;
755 }
756# endif
757 default:
758 {
759 vboxVBVAHostCommandComplete(ppdev, pCmd);
760 }
761 }
762}
763
764void vboxVHWACommandCheckHostCmds(PPDEV ppdev)
765{
766 VBVAHOSTCMD * pCmd;
767 int rc = ppdev->pfnHGSMIRequestCommands(ppdev->hMpHGSMI, HGSMI_CH_VBVA, &pCmd);
768 if(RT_SUCCESS(rc))
769 {
770 for(; pCmd; pCmd = pCmd->u.pNext)
771 {
772 vboxVBVAHostCommandHanlder(ppdev, pCmd);
773 }
774 }
775}
776
777void vboxVHWACommandSubmitAsynchByEvent (PPDEV ppdev, VBOXVHWACMD* pCmd, PEVENT pEvent)
778{
779// Assert(0);
780 pCmd->GuestVBVAReserved1 = (uintptr_t)pEvent;
781 pCmd->GuestVBVAReserved2 = 0;
782
783 /* complete it asynchronously by setting event */
784 pCmd->Flags |= VBOXVHWACMD_FLAG_ASYNCH_EVENT;
785 vboxHGSMIBufferSubmit (ppdev, pCmd);
786
787 if(!(ASMAtomicReadU32((volatile uint32_t *)&pCmd->Flags) & VBOXVHWACMD_FLAG_ASYNCH))
788 {
789 /* the command is completed */
790 EngSetEvent(pEvent);
791 }
792}
793
794BOOL vboxVHWACommandSubmit (PPDEV ppdev, VBOXVHWACMD* pCmd)
795{
796 PEVENT pEvent;
797 BOOL brc = EngCreateEvent(&pEvent);
798 Assert(brc);
799
800 if(brc)
801 {
802 pCmd->Flags = VBOXVHWACMD_FLAG_ASYNCH_IRQ;
803 vboxVHWACommandSubmitAsynchByEvent (ppdev, pCmd, pEvent);
804
805 brc = EngWaitForSingleObject(pEvent,
806 NULL /*IN PLARGE_INTEGER pTimeOut*/
807 );
808 Assert(brc);
809 if(brc)
810 {
811 EngDeleteEvent(pEvent);
812 }
813 }
814 return brc;
815}
816
817/* do not wait for completion */
818void vboxVHWACommandSubmitAsynch (PPDEV ppdev, VBOXVHWACMD* pCmd, PFNVBOXVHWACMDCOMPLETION pfnCompletion, void * pContext)
819{
820// Assert(0);
821 pCmd->GuestVBVAReserved1 = (uintptr_t)pfnCompletion;
822 pCmd->GuestVBVAReserved2 = (uintptr_t)pContext;
823
824 pCmd->Flags = 0;
825 vboxHGSMIBufferSubmit (ppdev, pCmd);
826
827 if(!(pCmd->Flags & VBOXVHWACMD_FLAG_ASYNCH))
828 {
829 /* the command is completed */
830 pfnCompletion(ppdev, pCmd, pContext);
831 }
832}
833
834void vboxVHWAFreeHostInfo1(PPDEV ppdev, VBOXVHWACMD_QUERYINFO1* pInfo)
835{
836 VBOXVHWACMD* pCmd = VBOXVHWACMD_HEAD(pInfo);
837 vboxVHWACommandFree (ppdev, pCmd);
838}
839
840void vboxVHWAFreeHostInfo2(PPDEV ppdev, VBOXVHWACMD_QUERYINFO2* pInfo)
841{
842 VBOXVHWACMD* pCmd = VBOXVHWACMD_HEAD(pInfo);
843 vboxVHWACommandFree (ppdev, pCmd);
844}
845
846VBOXVHWACMD_QUERYINFO1* vboxVHWAQueryHostInfo1(PPDEV ppdev)
847{
848 VBOXVHWACMD* pCmd = vboxVHWACommandCreate (ppdev, VBOXVHWACMD_TYPE_QUERY_INFO1, sizeof(VBOXVHWACMD_QUERYINFO1));
849 if (!pCmd)
850 {
851 DISPDBG((0, "VBoxDISP::vboxVHWAQueryHostInfo1: vboxVHWACommandCreate failed\n"));
852 return NULL;
853 }
854
855 if(vboxVHWACommandSubmit (ppdev, pCmd))
856 {
857 if(RT_SUCCESS(pCmd->rc))
858 {
859 return VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_QUERYINFO1);
860 }
861 }
862
863 vboxVHWACommandFree (ppdev, pCmd);
864 return NULL;
865}
866
867VBOXVHWACMD_QUERYINFO2* vboxVHWAQueryHostInfo2(PPDEV ppdev, uint32_t numFourCC)
868{
869 VBOXVHWACMD* pCmd = vboxVHWACommandCreate (ppdev, VBOXVHWACMD_TYPE_QUERY_INFO2, sizeof(VBOXVHWACMD_QUERYINFO2));
870 VBOXVHWACMD_QUERYINFO2 *pInfo2;
871 if (!pCmd)
872 {
873 DISPDBG((0, "VBoxDISP::vboxVHWAQueryHostInfo1: vboxVHWACommandCreate failed\n"));
874 return NULL;
875 }
876
877 pInfo2 = VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_QUERYINFO2);
878 pInfo2->numFourCC = numFourCC;
879
880 if(vboxVHWACommandSubmit (ppdev, pCmd))
881 {
882 if(RT_SUCCESS(pCmd->rc))
883 {
884 if(pInfo2->numFourCC == numFourCC)
885 {
886 return pInfo2;
887 }
888 }
889 }
890
891 vboxVHWACommandFree (ppdev, pCmd);
892 return NULL;
893}
894
895int vboxVHWAInitHostInfo1(PPDEV ppdev)
896{
897 VBOXVHWACMD_QUERYINFO1* pInfo = vboxVHWAQueryHostInfo1(ppdev);
898 if(!pInfo)
899 {
900 ppdev->vhwaInfo.bVHWAEnabled = false;
901 return VERR_OUT_OF_RESOURCES;
902 }
903
904 ppdev->vhwaInfo.caps = pInfo->caps;
905 ppdev->vhwaInfo.caps2 = pInfo->caps2;
906 ppdev->vhwaInfo.colorKeyCaps = pInfo->colorKeyCaps;
907 ppdev->vhwaInfo.stretchCaps = pInfo->stretchCaps;
908 ppdev->vhwaInfo.surfaceCaps = pInfo->surfaceCaps;
909 ppdev->vhwaInfo.numOverlays = pInfo->numOverlays;
910 ppdev->vhwaInfo.numFourCC = pInfo->numFourCC;
911 ppdev->vhwaInfo.bVHWAEnabled = (pInfo->cfgFlags & VBOXVHWA_CFG_ENABLED);
912 vboxVHWAFreeHostInfo1(ppdev, pInfo);
913 return VINF_SUCCESS;
914}
915
916int vboxVHWAInitHostInfo2(PPDEV ppdev, DWORD *pFourCC)
917{
918 VBOXVHWACMD_QUERYINFO2* pInfo = vboxVHWAQueryHostInfo2(ppdev, ppdev->vhwaInfo.numFourCC);
919 int rc = VINF_SUCCESS;
920
921 if(pInfo)
922 return VERR_OUT_OF_RESOURCES;
923
924 if(ppdev->vhwaInfo.numFourCC)
925 {
926 memcpy(pFourCC, pInfo->FourCC, ppdev->vhwaInfo.numFourCC * sizeof(pFourCC[0]));
927 }
928 else
929 {
930 Assert(0);
931 rc = VERR_GENERAL_FAILURE;
932 }
933
934 vboxVHWAFreeHostInfo2(ppdev, pInfo);
935
936 return rc;
937}
938
939int vboxVHWAEnable(PPDEV ppdev)
940{
941 int rc = VERR_GENERAL_FAILURE;
942 VBOXVHWACMD* pCmd = vboxVHWACommandCreate (ppdev, VBOXVHWACMD_TYPE_ENABLE, 0);
943 if (!pCmd)
944 {
945 DISPDBG((0, "VBoxDISP::vboxVHWAQueryHostInfo1: vboxVHWACommandCreate failed\n"));
946 return rc;
947 }
948
949 if(vboxVHWACommandSubmit (ppdev, pCmd))
950 {
951 if(RT_SUCCESS(pCmd->rc))
952 {
953 rc = VINF_SUCCESS;
954 }
955 }
956
957 vboxVHWACommandFree (ppdev, pCmd);
958 return rc;
959}
960
961int vboxVHWADisable(PPDEV ppdev)
962{
963 int rc = VERR_GENERAL_FAILURE;
964 VBOXVHWACMD* pCmd = vboxVHWACommandCreate (ppdev, VBOXVHWACMD_TYPE_DISABLE, 0);
965 if (!pCmd)
966 {
967 DISPDBG((0, "VBoxDISP::vboxVHWAQueryHostInfo1: vboxVHWACommandCreate failed\n"));
968 return rc;
969 }
970
971 if(vboxVHWACommandSubmit (ppdev, pCmd))
972 {
973 if(RT_SUCCESS(pCmd->rc))
974 {
975 rc = VINF_SUCCESS;
976 }
977 }
978
979 vboxVHWACommandFree (ppdev, pCmd);
980
981 vboxVHWACommandCheckHostCmds(ppdev);
982
983 return rc;
984}
985
986# endif
987
988void vboxVBVAHostCommandComplete(PPDEV ppdev, VBVAHOSTCMD * pCmd)
989{
990 ppdev->pfnHGSMICommandComplete(ppdev->hMpHGSMI, pCmd);
991}
992
993#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