VirtualBox

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

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

HGSMI/VBVA updates

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