VirtualBox

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

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

build fix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.9 KB
Line 
1/* $Id: vbox.c 29260 2010-05-09 18:51:24Z vboxsync $ */
2/** @file
3 * Display - VirtualBox Win 2000/XP guest display driver, support functions.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Oracle Corporation
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
18#include "driver.h"
19
20#include <VBox/VMMDev.h>
21#include <VBox/VBoxGuest.h>
22#include <VBox/err.h>
23#include <iprt/asm.h>
24#include <iprt/asm-amd64-x86.h>
25
26/*
27 * There is a hardware ring buffer in the VBox VMMDev PCI memory space.
28 * All graphics commands go there serialized by vboxHwBufferBeginUpdate.
29 * and vboxHwBufferEndUpdate.
30 *
31 * off32Free is writing position. off32Data is reading position.
32 * off32Free == off32Data means buffer is empty.
33 * There must be always gap between off32Data and off32Free when data
34 * are in the buffer.
35 * Guest only changes off32Free, host changes off32Data.
36 */
37
38/* Forward declarations of internal functions. */
39static void vboxHwBufferFlush (PPDEV ppdev);
40static void vboxHwBufferPlaceDataAt (PPDEV ppdev, void *p, uint32_t cb, uint32_t offset);
41static BOOL vboxHwBufferWrite (PPDEV ppdev, const void *p, uint32_t cb);
42
43#ifndef VBOX_WITH_HGSMI
44/*
45 * Public hardware buffer methods.
46 */
47BOOL vboxVbvaEnable (PPDEV ppdev)
48{
49 BOOL bRc = FALSE;
50
51 ULONG returnedDataLength;
52 ULONG ulEnable = TRUE;
53
54 DISPDBG((1, "VBoxDisp::vboxVbvaEnable called\n"));
55
56 if (!ghsemHwBuffer)
57 {
58 return FALSE;
59 }
60
61 if (EngDeviceIoControl(ppdev->hDriver,
62 IOCTL_VIDEO_VBVA_ENABLE,
63 &ulEnable,
64 sizeof (ulEnable),
65 &ppdev->vbva,
66 sizeof (ppdev->vbva),
67 &returnedDataLength) == 0)
68 {
69 DISPDBG((1, "VBoxDisp::vboxVbvaEnable: vbva: pVbvaMemory = %p, pfnFlush = %p, pvFlush = %p.\n",
70 ppdev->vbva.pVbvaMemory, ppdev->vbva.pfnFlush, ppdev->vbva.pvFlush));
71
72 if (ppdev->vbva.pVbvaMemory
73 && ppdev->vbva.pfnFlush
74 && ppdev->vbva.pvFlush)
75 {
76 ppdev->fHwBufferOverflow = FALSE;
77 ppdev->pRecord = NULL;
78
79 /* All have been initialized. */
80 bRc = TRUE;
81 }
82 }
83
84 if (!bRc)
85 {
86 vboxVbvaDisable (ppdev);
87 }
88
89 return bRc;
90}
91
92void vboxVbvaDisable (PPDEV ppdev)
93{
94 DISPDBG((1, "VBoxDisp::vbvaDisable called.\n"));
95
96 RtlZeroMemory (&ppdev->vbva, sizeof (ppdev->vbva));
97
98 ppdev->fHwBufferOverflow = FALSE;
99 ppdev->pRecord = NULL;
100
101 return;
102}
103
104BOOL vboxHwBufferBeginUpdate (PPDEV ppdev)
105{
106 BOOL bRc = FALSE;
107
108 VBVAMEMORY *pVbvaMemory = ppdev->vbva.pVbvaMemory;
109
110 DISPDBG((1, "VBoxDisp::vboxHwBufferBeginUpdate called flags = 0x%08X\n", pVbvaMemory? pVbvaMemory->fu32ModeFlags: -1));
111
112 if ( pVbvaMemory
113 && (pVbvaMemory->fu32ModeFlags & VBVA_F_MODE_ENABLED))
114 {
115 uint32_t indexRecordNext;
116
117 EngAcquireSemaphore (ghsemHwBuffer);
118
119 VBVA_ASSERT (!ppdev->fHwBufferOverflow);
120 VBVA_ASSERT (ppdev->pRecord == NULL);
121
122 indexRecordNext = (pVbvaMemory->indexRecordFree + 1) % VBVA_MAX_RECORDS;
123
124 if (indexRecordNext == pVbvaMemory->indexRecordFirst)
125 {
126 /* All slots in the records queue are used. */
127 vboxHwBufferFlush (ppdev);
128 }
129
130 if (indexRecordNext == pVbvaMemory->indexRecordFirst)
131 {
132 /* Even after flush there is no place. Fail the request. */
133 DISPDBG((1, "VBoxDisp::vboxHwBufferBeginUpdate no space in the queue of records!!! first %d, last %d\n",
134 pVbvaMemory->indexRecordFirst, pVbvaMemory->indexRecordFree));
135 EngReleaseSemaphore (ghsemHwBuffer);
136 }
137 else
138 {
139 /* Initialize the record. */
140 VBVARECORD *pRecord = &pVbvaMemory->aRecords[pVbvaMemory->indexRecordFree];
141
142 pRecord->cbRecord = VBVA_F_RECORD_PARTIAL;
143
144 pVbvaMemory->indexRecordFree = indexRecordNext;
145
146 DISPDBG((1, "VBoxDisp::vboxHwBufferBeginUpdate indexRecordNext = %d\n", indexRecordNext));
147
148 /* Remember which record we are using. */
149 ppdev->pRecord = pRecord;
150
151 bRc = TRUE;
152 }
153 }
154
155 return bRc;
156}
157
158void vboxHwBufferEndUpdate (PPDEV ppdev)
159{
160 VBVAMEMORY *pVbvaMemory;
161 VBVARECORD *pRecord;
162
163 DISPDBG((1, "VBoxDisp::vboxHwBufferEndUpdate called\n"));
164
165 pVbvaMemory = ppdev->vbva.pVbvaMemory;
166 VBVA_ASSERT(pVbvaMemory);
167
168 pRecord = ppdev->pRecord;
169 VBVA_ASSERT (pRecord && (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL));
170
171 /* Mark the record completed. */
172 pRecord->cbRecord &= ~VBVA_F_RECORD_PARTIAL;
173
174 ppdev->fHwBufferOverflow = FALSE;
175 ppdev->pRecord = NULL;
176
177 EngReleaseSemaphore (ghsemHwBuffer);
178
179 return;
180}
181
182/*
183 * Private operations.
184 */
185static uint32_t vboxHwBufferAvail (VBVAMEMORY *pVbvaMemory)
186{
187 int32_t i32Diff = pVbvaMemory->off32Data - pVbvaMemory->off32Free;
188
189 return i32Diff > 0? i32Diff: VBVA_RING_BUFFER_SIZE + i32Diff;
190}
191
192static void vboxHwBufferFlush (PPDEV ppdev)
193{
194 VBVAMEMORY *pVbvaMemory = ppdev->vbva.pVbvaMemory;
195
196 VBVA_ASSERT (pVbvaMemory);
197
198 ppdev->vbva.pfnFlush (ppdev->vbva.pvFlush);
199
200 return;
201}
202
203static void vboxHwBufferPlaceDataAt (PPDEV ppdev, void *p, uint32_t cb, uint32_t offset)
204{
205 VBVAMEMORY *pVbvaMemory = ppdev->vbva.pVbvaMemory;
206
207 uint32_t u32BytesTillBoundary = VBVA_RING_BUFFER_SIZE - offset;
208 uint8_t *dst = &pVbvaMemory->au8RingBuffer[offset];
209 int32_t i32Diff = cb - u32BytesTillBoundary;
210
211 if (i32Diff <= 0)
212 {
213 /* Chunk will not cross buffer boundary. */
214 memcpy (dst, p, cb);
215 }
216 else
217 {
218 /* Chunk crosses buffer boundary. */
219 memcpy (dst, p, u32BytesTillBoundary);
220 memcpy (&pVbvaMemory->au8RingBuffer[0], (uint8_t *)p + u32BytesTillBoundary, i32Diff);
221 }
222
223 return;
224}
225
226static BOOL vboxHwBufferWrite (PPDEV ppdev, const void *p, uint32_t cb)
227{
228 VBVAMEMORY *pVbvaMemory;
229 VBVARECORD *pRecord;
230 uint32_t cbHwBufferAvail;
231
232 uint32_t cbWritten = 0;
233
234 VBVA_ASSERT(ppdev);
235
236 if (ppdev->fHwBufferOverflow)
237 {
238 return FALSE;
239 }
240
241 pVbvaMemory = ppdev->vbva.pVbvaMemory;
242 VBVA_ASSERT (pVbvaMemory->indexRecordFirst != pVbvaMemory->indexRecordFree);
243
244 pRecord = ppdev->pRecord;
245 VBVA_ASSERT (pRecord && (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL));
246
247 DISPDBG((1, "VW %d\n", cb));
248
249 cbHwBufferAvail = vboxHwBufferAvail (pVbvaMemory);
250
251 while (cb > 0)
252 {
253 uint32_t cbChunk = cb;
254
255// 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));
256
257 if (cbChunk >= cbHwBufferAvail)
258 {
259 DISPDBG((1, "VBoxDisp::vboxHwBufferWrite 1) avail %d, chunk %d\n", cbHwBufferAvail, cbChunk));
260
261 vboxHwBufferFlush (ppdev);
262
263 cbHwBufferAvail = vboxHwBufferAvail (pVbvaMemory);
264
265 if (cbChunk >= cbHwBufferAvail)
266 {
267 DISPDBG((1, "VBoxDisp::vboxHwBufferWrite: no place for %d bytes. Only %d bytes available after flush. Going to partial writes.\n", cb, cbHwBufferAvail));
268
269 if (cbHwBufferAvail <= VBVA_RING_BUFFER_THRESHOLD)
270 {
271 DISPDBG((1, "VBoxDisp::vboxHwBufferWrite: Buffer overflow!!!\n"));
272 ppdev->fHwBufferOverflow = TRUE;
273 VBVA_ASSERT(FALSE);
274 return FALSE;
275 }
276
277 cbChunk = cbHwBufferAvail - VBVA_RING_BUFFER_THRESHOLD;
278 }
279 }
280
281 VBVA_ASSERT(cbChunk <= cb);
282 VBVA_ASSERT(cbChunk <= vboxHwBufferAvail (pVbvaMemory));
283
284 vboxHwBufferPlaceDataAt (ppdev, (uint8_t *)p + cbWritten, cbChunk, pVbvaMemory->off32Free);
285
286 pVbvaMemory->off32Free = (pVbvaMemory->off32Free + cbChunk) % VBVA_RING_BUFFER_SIZE;
287 pRecord->cbRecord += cbChunk;
288 cbHwBufferAvail -= cbChunk;
289
290 cb -= cbChunk;
291 cbWritten += cbChunk;
292 }
293
294 return TRUE;
295}
296
297/*
298 * Public writer to hardware buffer.
299 */
300BOOL vboxWrite (PPDEV ppdev, const void *pv, uint32_t cb)
301{
302 return vboxHwBufferWrite (ppdev, pv, cb);
303}
304
305BOOL vboxOrderSupported (PPDEV ppdev, unsigned code)
306{
307 VBVAMEMORY *pVbvaMemory;
308
309 pVbvaMemory = ppdev->vbva.pVbvaMemory;
310
311 if (pVbvaMemory->fu32ModeFlags & VBVA_F_MODE_VRDP_ORDER_MASK)
312 {
313 /* Order masking enabled. */
314 if (pVbvaMemory->fu32SupportedOrders & (1 << code))
315 {
316 return TRUE;
317 }
318 }
319
320 return FALSE;
321}
322
323void VBoxProcessDisplayInfo(PPDEV ppdev)
324{
325 DWORD returnedDataLength;
326
327 DISPDBG((1, "Process: %d,%d\n", ppdev->ptlDevOrg.x, ppdev->ptlDevOrg.y));
328
329 EngDeviceIoControl(ppdev->hDriver,
330 IOCTL_VIDEO_INTERPRET_DISPLAY_MEMORY,
331 NULL,
332 0,
333 NULL,
334 0,
335 &returnedDataLength);
336}
337
338#else /* VBOX_WITH_HGSMI */
339
340static void vboxHGSMIBufferSubmit (PPDEV ppdev, void *p)
341{
342 HGSMIOFFSET offBuffer = HGSMIHeapBufferOffset (&ppdev->hgsmiDisplayHeap, p);
343
344 DISPDBG((0, "VBoxDISP::vboxHGSMIBufferSubmit: offset 0x%x\n", offBuffer));
345
346 ASMOutU32(ppdev->IOPortGuestCommand, offBuffer);
347}
348
349static BOOL vboxVBVAInformHost (PPDEV ppdev, BOOL bEnable)
350{
351 BOOL bRc = FALSE;
352
353 if (ppdev->bHGSMISupported)
354 {
355 void *p = HGSMIHeapAlloc (&ppdev->hgsmiDisplayHeap,
356 sizeof (VBVAENABLE),
357 HGSMI_CH_VBVA,
358 VBVA_ENABLE);
359 if (!p)
360 {
361 DISPDBG((0, "VBoxDISP::vboxVBVAInformHost: HGSMIHeapAlloc failed\n"));
362 }
363 else
364 {
365 VBVAENABLE *pEnable = (VBVAENABLE *)p;
366
367 pEnable->u32Flags = bEnable? VBVA_F_ENABLE: VBVA_F_DISABLE;
368 pEnable->u32Offset = ppdev->layout.offVBVABuffer;
369 pEnable->i32Result = VERR_NOT_SUPPORTED;
370
371 vboxHGSMIBufferSubmit (ppdev, p);
372
373 if (bEnable)
374 {
375 bRc = RT_SUCCESS(pEnable->i32Result);
376 }
377 else
378 {
379 bRc = TRUE;
380 }
381
382 HGSMIHeapFree (&ppdev->hgsmiDisplayHeap, p);
383 }
384 }
385
386 return bRc;
387}
388
389/*
390 * Public hardware buffer methods.
391 */
392BOOL vboxVbvaEnable (PPDEV ppdev)
393{
394 BOOL bRc = FALSE;
395
396 DISPDBG((1, "VBoxDisp::vboxVbvaEnable called ppdev %p, hgsmi %d, vbva %p\n", ppdev, ppdev->bHGSMISupported, ppdev->pVBVA));
397
398 if (ppdev->bHGSMISupported)
399 {
400 VBVABUFFER *pVBVA = (VBVABUFFER *)((uint8_t *)ppdev->pjScreen + ppdev->layout.offVBVABuffer);
401
402 DISPDBG((1, "VBoxDisp::vboxVbvaEnable screen %p vbva off 0x%x\n", ppdev->pjScreen, ppdev->layout.offVBVABuffer));
403
404 pVBVA->hostFlags.u32HostEvents = 0;
405 pVBVA->hostFlags.u32SupportedOrders = 0;
406 pVBVA->off32Data = 0;
407 pVBVA->off32Free = 0;
408 RtlZeroMemory (pVBVA->aRecords, sizeof (pVBVA->aRecords));
409 pVBVA->indexRecordFirst = 0;
410 pVBVA->indexRecordFree = 0;
411 pVBVA->cbPartialWriteThreshold = 256;
412 pVBVA->cbData = ppdev->layout.cbVBVABuffer - sizeof (VBVABUFFER) + sizeof (pVBVA->au8Data);
413
414 ppdev->fHwBufferOverflow = FALSE;
415 ppdev->pRecord = NULL;
416 ppdev->pVBVA = pVBVA;
417
418 bRc = vboxVBVAInformHost (ppdev, TRUE);
419 }
420
421 if (!bRc)
422 {
423 vboxVbvaDisable (ppdev);
424 }
425
426 return bRc;
427}
428
429void vboxVbvaDisable (PPDEV ppdev)
430{
431 DISPDBG((1, "VBoxDisp::vbvaDisable called.\n"));
432
433 ppdev->fHwBufferOverflow = FALSE;
434 ppdev->pRecord = NULL;
435 ppdev->pVBVA = NULL;
436
437 vboxVBVAInformHost (ppdev, FALSE);
438
439 return;
440}
441
442BOOL vboxHwBufferBeginUpdate (PPDEV ppdev)
443{
444 BOOL bRc = FALSE;
445
446 // DISPDBG((1, "VBoxDisp::vboxHwBufferBeginUpdate called flags = 0x%08X\n",
447 // ppdev->pVBVA? ppdev->pVBVA->u32HostEvents: -1));
448
449 if ( ppdev->pVBVA
450 && (ppdev->pVBVA->hostFlags.u32HostEvents & VBVA_F_MODE_ENABLED))
451 {
452 uint32_t indexRecordNext;
453
454 VBVA_ASSERT (!ppdev->fHwBufferOverflow);
455 VBVA_ASSERT (ppdev->pRecord == NULL);
456
457 indexRecordNext = (ppdev->pVBVA->indexRecordFree + 1) % VBVA_MAX_RECORDS;
458
459 if (indexRecordNext == ppdev->pVBVA->indexRecordFirst)
460 {
461 /* All slots in the records queue are used. */
462 vboxHwBufferFlush (ppdev);
463 }
464
465 if (indexRecordNext == ppdev->pVBVA->indexRecordFirst)
466 {
467 /* Even after flush there is no place. Fail the request. */
468 DISPDBG((1, "VBoxDisp::vboxHwBufferBeginUpdate no space in the queue of records!!! first %d, last %d\n",
469 ppdev->pVBVA->indexRecordFirst, ppdev->pVBVA->indexRecordFree));
470 }
471 else
472 {
473 /* Initialize the record. */
474 VBVARECORD *pRecord = &ppdev->pVBVA->aRecords[ppdev->pVBVA->indexRecordFree];
475
476 pRecord->cbRecord = VBVA_F_RECORD_PARTIAL;
477
478 ppdev->pVBVA->indexRecordFree = indexRecordNext;
479
480 // DISPDBG((1, "VBoxDisp::vboxHwBufferBeginUpdate indexRecordNext = %d\n", indexRecordNext));
481
482 /* Remember which record we are using. */
483 ppdev->pRecord = pRecord;
484
485 bRc = TRUE;
486 }
487 }
488
489 return bRc;
490}
491
492void vboxHwBufferEndUpdate (PPDEV ppdev)
493{
494 VBVARECORD *pRecord;
495
496 // DISPDBG((1, "VBoxDisp::vboxHwBufferEndUpdate called\n"));
497
498 VBVA_ASSERT(ppdev->pVBVA);
499
500 pRecord = ppdev->pRecord;
501 VBVA_ASSERT (pRecord && (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL));
502
503 /* Mark the record completed. */
504 pRecord->cbRecord &= ~VBVA_F_RECORD_PARTIAL;
505
506 ppdev->fHwBufferOverflow = FALSE;
507 ppdev->pRecord = NULL;
508
509 return;
510}
511
512/*
513 * Private operations.
514 */
515static uint32_t vboxHwBufferAvail (const VBVABUFFER *pVBVA)
516{
517 int32_t i32Diff = pVBVA->off32Data - pVBVA->off32Free;
518
519 return i32Diff > 0? i32Diff: pVBVA->cbData + i32Diff;
520}
521
522static void vboxHwBufferFlush (PPDEV ppdev)
523{
524 /* Issue the flush command. */
525 void *p = HGSMIHeapAlloc (&ppdev->hgsmiDisplayHeap,
526 sizeof (VBVAFLUSH),
527 HGSMI_CH_VBVA,
528 VBVA_FLUSH);
529 if (!p)
530 {
531 DISPDBG((0, "VBoxDISP::vboxHwBufferFlush: HGSMIHeapAlloc failed\n"));
532 }
533 else
534 {
535 VBVAFLUSH *pFlush = (VBVAFLUSH *)p;
536
537 pFlush->u32Reserved = 0;
538
539 vboxHGSMIBufferSubmit (ppdev, p);
540
541 HGSMIHeapFree (&ppdev->hgsmiDisplayHeap, p);
542 }
543
544 return;
545}
546
547static void vboxHwBufferPlaceDataAt (PPDEV ppdev, const void *p, uint32_t cb, uint32_t offset)
548{
549 VBVABUFFER *pVBVA = ppdev->pVBVA;
550 uint32_t u32BytesTillBoundary = pVBVA->cbData - offset;
551 uint8_t *dst = &pVBVA->au8Data[offset];
552 int32_t i32Diff = cb - u32BytesTillBoundary;
553
554 if (i32Diff <= 0)
555 {
556 /* Chunk will not cross buffer boundary. */
557 memcpy (dst, p, cb);
558 }
559 else
560 {
561 /* Chunk crosses buffer boundary. */
562 memcpy (dst, p, u32BytesTillBoundary);
563 memcpy (&pVBVA->au8Data[0], (uint8_t *)p + u32BytesTillBoundary, i32Diff);
564 }
565
566 return;
567}
568
569static BOOL vboxHwBufferWrite (PPDEV ppdev, const void *p, uint32_t cb)
570{
571 VBVARECORD *pRecord;
572 uint32_t cbHwBufferAvail;
573
574 uint32_t cbWritten = 0;
575
576 VBVABUFFER *pVBVA = ppdev->pVBVA;
577 VBVA_ASSERT(pVBVA);
578
579 if (!pVBVA || ppdev->fHwBufferOverflow)
580 {
581 return FALSE;
582 }
583
584 VBVA_ASSERT (pVBVA->indexRecordFirst != pVBVA->indexRecordFree);
585
586 pRecord = ppdev->pRecord;
587 VBVA_ASSERT (pRecord && (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL));
588
589 DISPDBG((1, "VW %d\n", cb));
590
591 cbHwBufferAvail = vboxHwBufferAvail (pVBVA);
592
593 while (cb > 0)
594 {
595 uint32_t cbChunk = cb;
596
597 // DISPDBG((1, "VBoxDisp::vboxHwBufferWrite pVBVA->off32Free %d, pRecord->cbRecord 0x%08X, cbHwBufferAvail %d, cb %d, cbWritten %d\n",
598 // pVBVA->off32Free, pRecord->cbRecord, cbHwBufferAvail, cb, cbWritten));
599
600 if (cbChunk >= cbHwBufferAvail)
601 {
602 DISPDBG((1, "VBoxDisp::vboxHwBufferWrite 1) avail %d, chunk %d\n", cbHwBufferAvail, cbChunk));
603
604 vboxHwBufferFlush (ppdev);
605
606 cbHwBufferAvail = vboxHwBufferAvail (pVBVA);
607
608 if (cbChunk >= cbHwBufferAvail)
609 {
610 DISPDBG((1, "VBoxDisp::vboxHwBufferWrite: no place for %d bytes. Only %d bytes available after flush. Going to partial writes.\n",
611 cb, cbHwBufferAvail));
612
613 if (cbHwBufferAvail <= pVBVA->cbPartialWriteThreshold)
614 {
615 DISPDBG((1, "VBoxDisp::vboxHwBufferWrite: Buffer overflow!!!\n"));
616 ppdev->fHwBufferOverflow = TRUE;
617 VBVA_ASSERT(FALSE);
618 return FALSE;
619 }
620
621 cbChunk = cbHwBufferAvail - pVBVA->cbPartialWriteThreshold;
622 }
623 }
624
625 VBVA_ASSERT(cbChunk <= cb);
626 VBVA_ASSERT(cbChunk <= vboxHwBufferAvail (pVBVA));
627
628 vboxHwBufferPlaceDataAt (ppdev, (uint8_t *)p + cbWritten, cbChunk, pVBVA->off32Free);
629
630 pVBVA->off32Free = (pVBVA->off32Free + cbChunk) % pVBVA->cbData;
631 pRecord->cbRecord += cbChunk;
632 cbHwBufferAvail -= cbChunk;
633
634 cb -= cbChunk;
635 cbWritten += cbChunk;
636 }
637
638 return TRUE;
639}
640
641/*
642 * Public writer to the hardware buffer.
643 */
644BOOL vboxWrite (PPDEV ppdev, const void *pv, uint32_t cb)
645{
646 return vboxHwBufferWrite (ppdev, pv, cb);
647}
648
649BOOL vboxOrderSupported (PPDEV ppdev, unsigned code)
650{
651 VBVABUFFER *pVBVA = ppdev->pVBVA;
652
653 if (!pVBVA)
654 {
655 return FALSE;
656 }
657
658 if (pVBVA->hostFlags.u32SupportedOrders & (1 << code))
659 {
660 return TRUE;
661 }
662
663 return FALSE;
664}
665
666void VBoxProcessDisplayInfo (PPDEV ppdev)
667{
668 if (ppdev->bHGSMISupported)
669 {
670 /* Issue the screen info command. */
671 void *p = HGSMIHeapAlloc (&ppdev->hgsmiDisplayHeap,
672 sizeof (VBVAINFOSCREEN),
673 HGSMI_CH_VBVA,
674 VBVA_INFO_SCREEN);
675 if (!p)
676 {
677 DISPDBG((0, "VBoxDISP::VBoxProcessDisplayInfo: HGSMIHeapAlloc failed\n"));
678 }
679 else
680 {
681 VBVAINFOSCREEN *pScreen = (VBVAINFOSCREEN *)p;
682
683 pScreen->u32ViewIndex = ppdev->iDevice;
684 pScreen->i32OriginX = ppdev->ptlDevOrg.x;
685 pScreen->i32OriginY = ppdev->ptlDevOrg.y;
686 pScreen->u32StartOffset = 0;
687 pScreen->u32LineSize = ppdev->lDeltaScreen > 0?ppdev->lDeltaScreen: -ppdev->lDeltaScreen;
688 pScreen->u32Width = ppdev->cxScreen;
689 pScreen->u32Height = ppdev->cyScreen;
690 pScreen->u16BitsPerPixel = (uint16_t)ppdev->ulBitCount;
691 pScreen->u16Flags = VBVA_SCREEN_F_ACTIVE;
692
693 vboxHGSMIBufferSubmit (ppdev, p);
694
695 HGSMIHeapFree (&ppdev->hgsmiDisplayHeap, p);
696 }
697 }
698
699 return;
700}
701
702# ifdef VBOX_WITH_VIDEOHWACCEL
703
704VBOXVHWACMD* vboxVHWACommandCreate (PPDEV ppdev, VBOXVHWACMD_TYPE enmCmd, VBOXVHWACMD_LENGTH cbCmd)
705{
706 VBOXVHWACMD* pHdr = (VBOXVHWACMD*)HGSMIHeapAlloc (&ppdev->hgsmiDisplayHeap,
707 cbCmd + VBOXVHWACMD_HEADSIZE(),
708 HGSMI_CH_VBVA,
709 VBVA_VHWA_CMD);
710 if (!pHdr)
711 {
712 DISPDBG((0, "VBoxDISP::vboxVHWACommandCreate: HGSMIHeapAlloc failed\n"));
713 }
714 else
715 {
716 memset(pHdr, 0, sizeof(VBOXVHWACMD));
717 pHdr->iDisplay = ppdev->iDevice;
718 pHdr->rc = VERR_GENERAL_FAILURE;
719 pHdr->enmCmd = enmCmd;
720 pHdr->cRefs = 1;
721 }
722
723 /* temporary hack */
724 vboxVHWACommandCheckHostCmds(ppdev);
725
726 return pHdr;
727}
728
729void vboxVHWACommandFree (PPDEV ppdev, VBOXVHWACMD* pCmd)
730{
731 HGSMIHeapFree (&ppdev->hgsmiDisplayHeap, pCmd);
732}
733
734static DECLCALLBACK(void) vboxVHWACommandCompletionCallbackEvent(PPDEV ppdev, VBOXVHWACMD * pCmd, void * pContext)
735{
736 VBOXPEVENT pEvent = (VBOXPEVENT)pContext;
737 LONG oldState = ppdev->VideoPortProcs.pfnSetEvent(ppdev->pVideoPortContext, pEvent);
738 Assert(!oldState);
739}
740
741static int vboxVHWAHanldeVHWACmdCompletion(PPDEV ppdev, VBVAHOSTCMD * pHostCmd)
742{
743 VBVAHOSTCMDVHWACMDCOMPLETE * pComplete = VBVAHOSTCMD_BODY(pHostCmd, VBVAHOSTCMDVHWACMDCOMPLETE);
744 VBOXVHWACMD* pComplCmd = (VBOXVHWACMD*)HGSMIOffsetToPointer (&ppdev->hgsmiDisplayHeap.area, pComplete->offCmd);
745 PFNVBOXVHWACMDCOMPLETION pfnCompletion = (PFNVBOXVHWACMDCOMPLETION)pComplCmd->GuestVBVAReserved1;
746 void * pContext = (void *)pComplCmd->GuestVBVAReserved2;
747
748 pfnCompletion(ppdev, pComplCmd, pContext);
749
750 vboxVBVAHostCommandComplete(ppdev, pHostCmd);
751
752 return 0;
753}
754
755static void vboxVBVAHostCommandHanlder(PPDEV ppdev, VBVAHOSTCMD * pCmd)
756{
757 int rc = VINF_SUCCESS;
758 switch(pCmd->customOpCode)
759 {
760# ifdef VBOX_WITH_VIDEOHWACCEL
761 case VBVAHG_DCUSTOM_VHWA_CMDCOMPLETE:
762 {
763 vboxVHWAHanldeVHWACmdCompletion(ppdev, pCmd);
764 break;
765 }
766# endif
767 default:
768 {
769 Assert(0);
770 vboxVBVAHostCommandComplete(ppdev, pCmd);
771 }
772 }
773}
774
775void vboxVHWACommandCheckHostCmds(PPDEV ppdev)
776{
777 VBVAHOSTCMD * pCmd, * pNextCmd;
778 int rc = ppdev->pfnHGSMIRequestCommands(ppdev->hMpHGSMI, HGSMI_CH_VBVA, &pCmd);
779 /* don't assert here, otherwise NT4 will be unhappy */
780 if(RT_SUCCESS(rc))
781 {
782 for(;pCmd; pCmd = pNextCmd)
783 {
784 pNextCmd = pCmd->u.pNext;
785 vboxVBVAHostCommandHanlder(ppdev, pCmd);
786 }
787 }
788}
789
790void vboxVHWACommandSubmitAsynchByEvent (PPDEV ppdev, VBOXVHWACMD* pCmd, VBOXPEVENT pEvent)
791{
792// Assert(0);
793 pCmd->GuestVBVAReserved1 = (uintptr_t)pEvent;
794 pCmd->GuestVBVAReserved2 = 0;
795 /* ensure the command is not removed until we're processing it */
796 vbvaVHWACommandRetain(ppdev, pCmd);
797
798 /* complete it asynchronously by setting event */
799 pCmd->Flags |= VBOXVHWACMD_FLAG_GH_ASYNCH_EVENT;
800 vboxHGSMIBufferSubmit (ppdev, pCmd);
801
802 if(!(ASMAtomicReadU32((volatile uint32_t *)&pCmd->Flags) & VBOXVHWACMD_FLAG_HG_ASYNCH))
803 {
804 /* the command is completed */
805 ppdev->VideoPortProcs.pfnSetEvent(ppdev->pVideoPortContext, pEvent);
806 }
807
808 vbvaVHWACommandRelease(ppdev, pCmd);
809}
810
811BOOL vboxVHWACommandSubmit (PPDEV ppdev, VBOXVHWACMD* pCmd)
812{
813 VBOXPEVENT pEvent;
814 VBOXVP_STATUS rc = ppdev->VideoPortProcs.pfnCreateEvent(ppdev->pVideoPortContext, VBOXNOTIFICATION_EVENT, NULL, &pEvent);
815 /* don't assert here, otherwise NT4 will be unhappy */
816 if(rc == VBOXNO_ERROR)
817 {
818 pCmd->Flags |= VBOXVHWACMD_FLAG_GH_ASYNCH_IRQ;
819 vboxVHWACommandSubmitAsynchByEvent (ppdev, pCmd, pEvent);
820
821 rc = ppdev->VideoPortProcs.pfnWaitForSingleObject(ppdev->pVideoPortContext, pEvent,
822 NULL /*IN PLARGE_INTEGER pTimeOut*/
823 );
824 Assert(rc == VBOXNO_ERROR);
825 if(rc == VBOXNO_ERROR)
826 {
827 ppdev->VideoPortProcs.pfnDeleteEvent(ppdev->pVideoPortContext, pEvent);
828 }
829 }
830 return rc == VBOXNO_ERROR;
831}
832
833/* do not wait for completion */
834void vboxVHWACommandSubmitAsynch (PPDEV ppdev, VBOXVHWACMD* pCmd, PFNVBOXVHWACMDCOMPLETION pfnCompletion, void * pContext)
835{
836// Assert(0);
837 pCmd->GuestVBVAReserved1 = (uintptr_t)pfnCompletion;
838 pCmd->GuestVBVAReserved2 = (uintptr_t)pContext;
839 vbvaVHWACommandRetain(ppdev, pCmd);
840
841 vboxHGSMIBufferSubmit (ppdev, pCmd);
842
843 if(!(pCmd->Flags & VBOXVHWACMD_FLAG_HG_ASYNCH))
844 {
845 /* the command is completed */
846 pfnCompletion(ppdev, pCmd, pContext);
847 }
848
849 vbvaVHWACommandRelease(ppdev, pCmd);
850}
851
852static DECLCALLBACK(void) vboxVHWAFreeCmdCompletion(PPDEV ppdev, VBOXVHWACMD * pCmd, void * pContext)
853{
854 vbvaVHWACommandRelease(ppdev, pCmd);
855}
856
857void vboxVHWACommandSubmitAsynchAndComplete (PPDEV ppdev, VBOXVHWACMD* pCmd)
858{
859// Assert(0);
860 pCmd->GuestVBVAReserved1 = (uintptr_t)vboxVHWAFreeCmdCompletion;
861
862 vbvaVHWACommandRetain(ppdev, pCmd);
863
864 pCmd->Flags |= VBOXVHWACMD_FLAG_GH_ASYNCH_NOCOMPLETION;
865
866 vboxHGSMIBufferSubmit (ppdev, pCmd);
867
868 if(!(pCmd->Flags & VBOXVHWACMD_FLAG_HG_ASYNCH)
869 || pCmd->Flags & VBOXVHWACMD_FLAG_HG_ASYNCH_RETURNED)
870 {
871 /* the command is completed */
872 vboxVHWAFreeCmdCompletion(ppdev, pCmd, NULL);
873 }
874
875 vbvaVHWACommandRelease(ppdev, pCmd);
876}
877
878void vboxVHWAFreeHostInfo1(PPDEV ppdev, VBOXVHWACMD_QUERYINFO1* pInfo)
879{
880 VBOXVHWACMD* pCmd = VBOXVHWACMD_HEAD(pInfo);
881 vbvaVHWACommandRelease (ppdev, pCmd);
882}
883
884void vboxVHWAFreeHostInfo2(PPDEV ppdev, VBOXVHWACMD_QUERYINFO2* pInfo)
885{
886 VBOXVHWACMD* pCmd = VBOXVHWACMD_HEAD(pInfo);
887 vbvaVHWACommandRelease (ppdev, pCmd);
888}
889
890VBOXVHWACMD_QUERYINFO1* vboxVHWAQueryHostInfo1(PPDEV ppdev)
891{
892 VBOXVHWACMD* pCmd = vboxVHWACommandCreate (ppdev, VBOXVHWACMD_TYPE_QUERY_INFO1, sizeof(VBOXVHWACMD_QUERYINFO1));
893 VBOXVHWACMD_QUERYINFO1 *pInfo1;
894 if (!pCmd)
895 {
896 DISPDBG((0, "VBoxDISP::vboxVHWAQueryHostInfo1: vboxVHWACommandCreate failed\n"));
897 return NULL;
898 }
899
900 if (!pCmd)
901 {
902 DISPDBG((0, "VBoxDISP::vboxVHWAQueryHostInfo1: vboxVHWACommandCreate failed\n"));
903 return NULL;
904 }
905
906 pInfo1 = VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_QUERYINFO1);
907 pInfo1->u.in.guestVersion.maj = VBOXVHWA_VERSION_MAJ;
908 pInfo1->u.in.guestVersion.min = VBOXVHWA_VERSION_MIN;
909 pInfo1->u.in.guestVersion.bld = VBOXVHWA_VERSION_BLD;
910 pInfo1->u.in.guestVersion.reserved = VBOXVHWA_VERSION_RSV;
911
912 if(vboxVHWACommandSubmit (ppdev, pCmd))
913 {
914 if(RT_SUCCESS(pCmd->rc))
915 {
916 return VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_QUERYINFO1);
917 }
918 }
919
920 vbvaVHWACommandRelease (ppdev, pCmd);
921 return NULL;
922}
923
924VBOXVHWACMD_QUERYINFO2* vboxVHWAQueryHostInfo2(PPDEV ppdev, uint32_t numFourCC)
925{
926 VBOXVHWACMD* pCmd = vboxVHWACommandCreate (ppdev, VBOXVHWACMD_TYPE_QUERY_INFO2, VBOXVHWAINFO2_SIZE(numFourCC));
927 VBOXVHWACMD_QUERYINFO2 *pInfo2;
928 if (!pCmd)
929 {
930 DISPDBG((0, "VBoxDISP::vboxVHWAQueryHostInfo2: vboxVHWACommandCreate failed\n"));
931 return NULL;
932 }
933
934 pInfo2 = VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_QUERYINFO2);
935 pInfo2->numFourCC = numFourCC;
936
937 if(vboxVHWACommandSubmit (ppdev, pCmd))
938 {
939 if(RT_SUCCESS(pCmd->rc))
940 {
941 if(pInfo2->numFourCC == numFourCC)
942 {
943 return pInfo2;
944 }
945 }
946 }
947
948 vbvaVHWACommandRelease (ppdev, pCmd);
949 return NULL;
950}
951
952int vboxVHWAInitHostInfo1(PPDEV ppdev)
953{
954 VBOXVHWACMD_QUERYINFO1* pInfo;
955
956 if (!ppdev->bHGSMISupported)
957 return VERR_NOT_SUPPORTED;
958
959 pInfo = vboxVHWAQueryHostInfo1(ppdev);
960 if(!pInfo)
961 {
962 ppdev->vhwaInfo.bVHWAEnabled = false;
963 return VERR_OUT_OF_RESOURCES;
964 }
965
966 ppdev->vhwaInfo.caps = pInfo->u.out.caps;
967 ppdev->vhwaInfo.caps2 = pInfo->u.out.caps2;
968 ppdev->vhwaInfo.colorKeyCaps = pInfo->u.out.colorKeyCaps;
969 ppdev->vhwaInfo.stretchCaps = pInfo->u.out.stretchCaps;
970 ppdev->vhwaInfo.surfaceCaps = pInfo->u.out.surfaceCaps;
971 ppdev->vhwaInfo.numOverlays = pInfo->u.out.numOverlays;
972 ppdev->vhwaInfo.numFourCC = pInfo->u.out.numFourCC;
973 ppdev->vhwaInfo.bVHWAEnabled = (pInfo->u.out.cfgFlags & VBOXVHWA_CFG_ENABLED);
974 vboxVHWAFreeHostInfo1(ppdev, pInfo);
975 return VINF_SUCCESS;
976}
977
978int vboxVHWAInitHostInfo2(PPDEV ppdev, DWORD *pFourCC)
979{
980 VBOXVHWACMD_QUERYINFO2* pInfo;
981 int rc = VINF_SUCCESS;
982
983 if (!ppdev->bHGSMISupported)
984 return VERR_NOT_SUPPORTED;
985
986 pInfo = vboxVHWAQueryHostInfo2(ppdev, ppdev->vhwaInfo.numFourCC);
987
988 Assert(pInfo);
989 if(!pInfo)
990 return VERR_OUT_OF_RESOURCES;
991
992 if(ppdev->vhwaInfo.numFourCC)
993 {
994 memcpy(pFourCC, pInfo->FourCC, ppdev->vhwaInfo.numFourCC * sizeof(pFourCC[0]));
995 }
996 else
997 {
998 Assert(0);
999 rc = VERR_GENERAL_FAILURE;
1000 }
1001
1002 vboxVHWAFreeHostInfo2(ppdev, pInfo);
1003
1004 return rc;
1005}
1006
1007int vboxVHWAEnable(PPDEV ppdev)
1008{
1009 int rc = VERR_GENERAL_FAILURE;
1010 VBOXVHWACMD* pCmd;
1011
1012 if (!ppdev->bHGSMISupported)
1013 return VERR_NOT_SUPPORTED;
1014
1015 pCmd = vboxVHWACommandCreate (ppdev, VBOXVHWACMD_TYPE_ENABLE, 0);
1016 if (!pCmd)
1017 {
1018 DISPDBG((0, "VBoxDISP::vboxVHWAEnable: vboxVHWACommandCreate failed\n"));
1019 return rc;
1020 }
1021
1022 if(vboxVHWACommandSubmit (ppdev, pCmd))
1023 {
1024 if(RT_SUCCESS(pCmd->rc))
1025 {
1026 rc = VINF_SUCCESS;
1027 }
1028 }
1029
1030 vbvaVHWACommandRelease (ppdev, pCmd);
1031 return rc;
1032}
1033
1034int vboxVHWADisable(PPDEV ppdev)
1035{
1036 int rc = VERR_GENERAL_FAILURE;
1037 VBOXVHWACMD* pCmd;
1038
1039 if (!ppdev->bHGSMISupported)
1040 return VERR_NOT_SUPPORTED;
1041
1042 pCmd = vboxVHWACommandCreate (ppdev, VBOXVHWACMD_TYPE_DISABLE, 0);
1043 if (!pCmd)
1044 {
1045 DISPDBG((0, "VBoxDISP::vboxVHWADisable: vboxVHWACommandCreate failed\n"));
1046 return rc;
1047 }
1048
1049 if(vboxVHWACommandSubmit (ppdev, pCmd))
1050 {
1051 if(RT_SUCCESS(pCmd->rc))
1052 {
1053 rc = VINF_SUCCESS;
1054 }
1055 }
1056
1057 vbvaVHWACommandRelease (ppdev, pCmd);
1058
1059 vboxVHWACommandCheckHostCmds(ppdev);
1060
1061 return rc;
1062}
1063
1064void vboxVHWAInit(PPDEV ppdev)
1065{
1066 VHWAQUERYINFO info;
1067 DWORD returnedDataLength;
1068 DWORD err;
1069
1070 memset(&info, 0, sizeof (info));
1071
1072 err = EngDeviceIoControl(ppdev->hDriver,
1073 IOCTL_VIDEO_VHWA_QUERY_INFO,
1074 NULL,
1075 0,
1076 &info,
1077 sizeof(info),
1078 &returnedDataLength);
1079 Assert(!err);
1080 if(!err)
1081 {
1082 ppdev->vhwaInfo.offVramBase = info.offVramBase;
1083 ppdev->vhwaInfo.bVHWAInited = TRUE;
1084 }
1085 else
1086 ppdev->vhwaInfo.bVHWAInited = FALSE;
1087}
1088
1089# endif
1090
1091void vboxVBVAHostCommandComplete(PPDEV ppdev, VBVAHOSTCMD * pCmd)
1092{
1093 ppdev->pfnHGSMICommandComplete(ppdev->hMpHGSMI, pCmd);
1094}
1095
1096#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