VirtualBox

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

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

hgsmi/guest video driver: backwards compatibility with < WinXP: make newer videoport functions picked up at runtime

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