VirtualBox

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

Last change on this file since 22099 was 21939, checked in by vboxsync, 16 years ago

Video Hw Accel: debugging & better color support (still debugging & perf enhancements needed)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.3 KB
Line 
1/* $Id: vbox.c 21939 2009-08-03 11:52:51Z 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_GH_ASYNCH_EVENT;
785 vboxHGSMIBufferSubmit (ppdev, pCmd);
786
787 if(!(ASMAtomicReadU32((volatile uint32_t *)&pCmd->Flags) & VBOXVHWACMD_FLAG_HG_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_GH_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 vboxHGSMIBufferSubmit (ppdev, pCmd);
825
826 if(!(pCmd->Flags & VBOXVHWACMD_FLAG_HG_ASYNCH))
827 {
828 /* the command is completed */
829 pfnCompletion(ppdev, pCmd, pContext);
830 }
831}
832
833static DECLCALLBACK(void) vboxVHWAFreeCmdCompletion(PPDEV ppdev, VBOXVHWACMD * pCmd, void * pContext)
834{
835 vboxVHWACommandFree(ppdev, pCmd);
836}
837
838void vboxVHWACommandSubmitAsynchAndComplete (PPDEV ppdev, VBOXVHWACMD* pCmd)
839{
840// Assert(0);
841 pCmd->GuestVBVAReserved1 = (uintptr_t)vboxVHWAFreeCmdCompletion;
842
843 pCmd->Flags |= VBOXVHWACMD_FLAG_GH_ASYNCH_NOCOMPLETION;
844
845 vboxHGSMIBufferSubmit (ppdev, pCmd);
846
847 if(!(pCmd->Flags & VBOXVHWACMD_FLAG_HG_ASYNCH)
848 || pCmd->Flags & VBOXVHWACMD_FLAG_HG_ASYNCH_RETURNED)
849 {
850 /* the command is completed */
851 vboxVHWAFreeCmdCompletion(ppdev, pCmd, NULL);
852 }
853}
854
855void vboxVHWAFreeHostInfo1(PPDEV ppdev, VBOXVHWACMD_QUERYINFO1* pInfo)
856{
857 VBOXVHWACMD* pCmd = VBOXVHWACMD_HEAD(pInfo);
858 vboxVHWACommandFree (ppdev, pCmd);
859}
860
861void vboxVHWAFreeHostInfo2(PPDEV ppdev, VBOXVHWACMD_QUERYINFO2* pInfo)
862{
863 VBOXVHWACMD* pCmd = VBOXVHWACMD_HEAD(pInfo);
864 vboxVHWACommandFree (ppdev, pCmd);
865}
866
867VBOXVHWACMD_QUERYINFO1* vboxVHWAQueryHostInfo1(PPDEV ppdev)
868{
869 VBOXVHWACMD* pCmd = vboxVHWACommandCreate (ppdev, VBOXVHWACMD_TYPE_QUERY_INFO1, sizeof(VBOXVHWACMD_QUERYINFO1));
870 if (!pCmd)
871 {
872 DISPDBG((0, "VBoxDISP::vboxVHWAQueryHostInfo1: vboxVHWACommandCreate failed\n"));
873 return NULL;
874 }
875
876 if(vboxVHWACommandSubmit (ppdev, pCmd))
877 {
878 if(RT_SUCCESS(pCmd->rc))
879 {
880 return VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_QUERYINFO1);
881 }
882 }
883
884 vboxVHWACommandFree (ppdev, pCmd);
885 return NULL;
886}
887
888VBOXVHWACMD_QUERYINFO2* vboxVHWAQueryHostInfo2(PPDEV ppdev, uint32_t numFourCC)
889{
890 VBOXVHWACMD* pCmd = vboxVHWACommandCreate (ppdev, VBOXVHWACMD_TYPE_QUERY_INFO2, sizeof(VBOXVHWACMD_QUERYINFO2));
891 VBOXVHWACMD_QUERYINFO2 *pInfo2;
892 if (!pCmd)
893 {
894 DISPDBG((0, "VBoxDISP::vboxVHWAQueryHostInfo1: vboxVHWACommandCreate failed\n"));
895 return NULL;
896 }
897
898 pInfo2 = VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_QUERYINFO2);
899 pInfo2->numFourCC = numFourCC;
900
901 if(vboxVHWACommandSubmit (ppdev, pCmd))
902 {
903 if(RT_SUCCESS(pCmd->rc))
904 {
905 if(pInfo2->numFourCC == numFourCC)
906 {
907 return pInfo2;
908 }
909 }
910 }
911
912 vboxVHWACommandFree (ppdev, pCmd);
913 return NULL;
914}
915
916int vboxVHWAInitHostInfo1(PPDEV ppdev)
917{
918 VBOXVHWACMD_QUERYINFO1* pInfo = vboxVHWAQueryHostInfo1(ppdev);
919 if(!pInfo)
920 {
921 ppdev->vhwaInfo.bVHWAEnabled = false;
922 return VERR_OUT_OF_RESOURCES;
923 }
924
925 ppdev->vhwaInfo.caps = pInfo->caps;
926 ppdev->vhwaInfo.caps2 = pInfo->caps2;
927 ppdev->vhwaInfo.colorKeyCaps = pInfo->colorKeyCaps;
928 ppdev->vhwaInfo.stretchCaps = pInfo->stretchCaps;
929 ppdev->vhwaInfo.surfaceCaps = pInfo->surfaceCaps;
930 ppdev->vhwaInfo.numOverlays = pInfo->numOverlays;
931 ppdev->vhwaInfo.numFourCC = pInfo->numFourCC;
932 ppdev->vhwaInfo.bVHWAEnabled = (pInfo->cfgFlags & VBOXVHWA_CFG_ENABLED);
933 vboxVHWAFreeHostInfo1(ppdev, pInfo);
934 return VINF_SUCCESS;
935}
936
937int vboxVHWAInitHostInfo2(PPDEV ppdev, DWORD *pFourCC)
938{
939 VBOXVHWACMD_QUERYINFO2* pInfo = vboxVHWAQueryHostInfo2(ppdev, ppdev->vhwaInfo.numFourCC);
940 int rc = VINF_SUCCESS;
941
942 Assert(pInfo);
943 if(!pInfo)
944 return VERR_OUT_OF_RESOURCES;
945
946 if(ppdev->vhwaInfo.numFourCC)
947 {
948 memcpy(pFourCC, pInfo->FourCC, ppdev->vhwaInfo.numFourCC * sizeof(pFourCC[0]));
949 }
950 else
951 {
952 Assert(0);
953 rc = VERR_GENERAL_FAILURE;
954 }
955
956 vboxVHWAFreeHostInfo2(ppdev, pInfo);
957
958 return rc;
959}
960
961int vboxVHWAEnable(PPDEV ppdev)
962{
963 int rc = VERR_GENERAL_FAILURE;
964 VBOXVHWACMD* pCmd = vboxVHWACommandCreate (ppdev, VBOXVHWACMD_TYPE_ENABLE, 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 return rc;
981}
982
983int vboxVHWADisable(PPDEV ppdev)
984{
985 int rc = VERR_GENERAL_FAILURE;
986 VBOXVHWACMD* pCmd = vboxVHWACommandCreate (ppdev, VBOXVHWACMD_TYPE_DISABLE, 0);
987 if (!pCmd)
988 {
989 DISPDBG((0, "VBoxDISP::vboxVHWAQueryHostInfo1: vboxVHWACommandCreate failed\n"));
990 return rc;
991 }
992
993 if(vboxVHWACommandSubmit (ppdev, pCmd))
994 {
995 if(RT_SUCCESS(pCmd->rc))
996 {
997 rc = VINF_SUCCESS;
998 }
999 }
1000
1001 vboxVHWACommandFree (ppdev, pCmd);
1002
1003 vboxVHWACommandCheckHostCmds(ppdev);
1004
1005 return rc;
1006}
1007
1008# endif
1009
1010void vboxVBVAHostCommandComplete(PPDEV ppdev, VBVAHOSTCMD * pCmd)
1011{
1012 ppdev->pfnHGSMICommandComplete(ppdev->hMpHGSMI, pCmd);
1013}
1014
1015#endif /* VBOX_WITH_HGSMI */
Note: See TracBrowser for help on using the repository browser.

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