VirtualBox

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

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