VirtualBox

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

Last change on this file since 4071 was 4071, checked in by vboxsync, 17 years ago

Biggest check-in ever. New source code headers for all (C) innotek files.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.2 KB
Line 
1/** @file
2 *
3 * VBoxGuest -- VirtualBox Win 2000/XP guest display driver
4 *
5 * VBox support functions.
6 *
7 * Copyright (C) 2006-2007 innotek GmbH
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 as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include "driver.h"
19
20#include <VBox/VBoxGuest.h>
21#include <VBox/err.h>
22#include <iprt/asm.h>
23
24/*
25 * There is a hardware ring buffer in the VBox VMMDev PCI memory space.
26 * All graphics commands go there serialized by vboxHwBufferBeginUpdate.
27 * and vboxHwBufferEndUpdate.
28 *
29 * off32Free is writing position. off32Data is reading position.
30 * off32Free == off32Data means buffer is empty.
31 * There must be always gap between off32Data and off32Free when data
32 * are in the buffer.
33 * Guest only changes off32Free, host changes off32Data.
34 */
35
36/* Forward declarations of internal functions. */
37static void vboxHwBufferFlush (PPDEV ppdev);
38static void vboxHwBufferPlaceDataAt (PPDEV ppdev, void *p, uint32_t cb, uint32_t offset);
39static BOOL vboxHwBufferWrite (PPDEV ppdev, const void *p, uint32_t cb);
40
41/*
42 * Public hardware buffer methods.
43 */
44BOOL vboxVbvaEnable (PPDEV ppdev)
45{
46 BOOL bRc = FALSE;
47
48 ULONG returnedDataLength;
49 ULONG ulEnable = TRUE;
50
51 DISPDBG((1, "VBoxDisp::vboxVbvaEnable called\n"));
52
53 if (!ghsemHwBuffer)
54 {
55 return FALSE;
56 }
57
58 if (EngDeviceIoControl(ppdev->hDriver,
59 IOCTL_VIDEO_VBVA_ENABLE,
60 &ulEnable,
61 sizeof (ulEnable),
62 &ppdev->vbva,
63 sizeof (ppdev->vbva),
64 &returnedDataLength) == 0)
65 {
66 DISPDBG((1, "VBoxDisp::vboxVbvaEnable: vbva: pVbvaMemory = %p, pfnFlush = %p, pvFlush = %p.\n",
67 ppdev->vbva.pVbvaMemory, ppdev->vbva.pfnFlush, ppdev->vbva.pvFlush));
68
69 if (ppdev->vbva.pVbvaMemory
70 && ppdev->vbva.pfnFlush
71 && ppdev->vbva.pvFlush)
72 {
73 ppdev->fHwBufferOverflow = FALSE;
74 ppdev->pRecord = NULL;
75
76 /* All have been initialized. */
77 bRc = TRUE;
78 }
79 }
80
81 if (!bRc)
82 {
83 vboxVbvaDisable (ppdev);
84 }
85
86 return bRc;
87}
88
89void vboxVbvaDisable (PPDEV ppdev)
90{
91 DISPDBG((1, "VBoxDisp::vbvaDisable called.\n"));
92
93 RtlZeroMemory (&ppdev->vbva, sizeof (ppdev->vbva));
94
95 ppdev->fHwBufferOverflow = FALSE;
96 ppdev->pRecord = NULL;
97
98 return;
99}
100
101BOOL vboxHwBufferBeginUpdate (PPDEV ppdev)
102{
103 BOOL bRc = FALSE;
104
105 VBVAMEMORY *pVbvaMemory = ppdev->vbva.pVbvaMemory;
106
107 DISPDBG((1, "VBoxDisp::vboxHwBufferBeginUpdate called flags = 0x%08X\n", pVbvaMemory? pVbvaMemory->fu32ModeFlags: -1));
108
109 if ( pVbvaMemory
110 && (pVbvaMemory->fu32ModeFlags & VBVA_F_MODE_ENABLED))
111 {
112 uint32_t indexRecordNext;
113
114 EngAcquireSemaphore (ghsemHwBuffer);
115
116 VBVA_ASSERT (!ppdev->fHwBufferOverflow);
117 VBVA_ASSERT (ppdev->pRecord == NULL);
118
119 indexRecordNext = (pVbvaMemory->indexRecordFree + 1) % VBVA_MAX_RECORDS;
120
121 if (indexRecordNext == pVbvaMemory->indexRecordFirst)
122 {
123 /* All slots in the records queue are used. */
124 vboxHwBufferFlush (ppdev);
125 }
126
127 if (indexRecordNext == pVbvaMemory->indexRecordFirst)
128 {
129 /* Even after flush there is no place. Fail the request. */
130 DISPDBG((1, "VBoxDisp::vboxHwBufferBeginUpdate no space in the queue of records!!! first %d, last %d\n",
131 pVbvaMemory->indexRecordFirst, pVbvaMemory->indexRecordFree));
132 EngReleaseSemaphore (ghsemHwBuffer);
133 }
134 else
135 {
136 /* Initialize the record. */
137 VBVARECORD *pRecord = &pVbvaMemory->aRecords[pVbvaMemory->indexRecordFree];
138
139 pRecord->cbRecord = VBVA_F_RECORD_PARTIAL;
140
141 pVbvaMemory->indexRecordFree = indexRecordNext;
142
143 DISPDBG((1, "VBoxDisp::vboxHwBufferBeginUpdate indexRecordNext = %d\n", indexRecordNext));
144
145 /* Remember which record we are using. */
146 ppdev->pRecord = pRecord;
147
148 bRc = TRUE;
149 }
150 }
151
152 return bRc;
153}
154
155void vboxHwBufferEndUpdate (PPDEV ppdev)
156{
157 VBVAMEMORY *pVbvaMemory;
158 VBVARECORD *pRecord;
159
160 DISPDBG((1, "VBoxDisp::vboxHwBufferEndUpdate called\n"));
161
162 pVbvaMemory = ppdev->vbva.pVbvaMemory;
163 VBVA_ASSERT(pVbvaMemory);
164
165 pRecord = ppdev->pRecord;
166 VBVA_ASSERT (pRecord && (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL));
167
168 /* Mark the record completed. */
169 pRecord->cbRecord &= ~VBVA_F_RECORD_PARTIAL;
170
171 ppdev->fHwBufferOverflow = FALSE;
172 ppdev->pRecord = NULL;
173
174 EngReleaseSemaphore (ghsemHwBuffer);
175
176 return;
177}
178
179/*
180 * Private operations.
181 */
182static uint32_t vboxHwBufferAvail (VBVAMEMORY *pVbvaMemory)
183{
184 int32_t i32Diff = pVbvaMemory->off32Data - pVbvaMemory->off32Free;
185
186 return i32Diff > 0? i32Diff: VBVA_RING_BUFFER_SIZE + i32Diff;
187}
188
189static void vboxHwBufferFlush (PPDEV ppdev)
190{
191 VBVAMEMORY *pVbvaMemory = ppdev->vbva.pVbvaMemory;
192
193 VBVA_ASSERT (pVbvaMemory);
194
195 ppdev->vbva.pfnFlush (ppdev->vbva.pvFlush);
196
197 return;
198}
199
200static void vboxHwBufferPlaceDataAt (PPDEV ppdev, void *p, uint32_t cb, uint32_t offset)
201{
202 VBVAMEMORY *pVbvaMemory = ppdev->vbva.pVbvaMemory;
203
204 uint32_t u32BytesTillBoundary = VBVA_RING_BUFFER_SIZE - offset;
205 uint8_t *dst = &pVbvaMemory->au8RingBuffer[offset];
206 int32_t i32Diff = cb - u32BytesTillBoundary;
207
208 if (i32Diff <= 0)
209 {
210 /* Chunk will not cross buffer boundary. */
211 memcpy (dst, p, cb);
212 }
213 else
214 {
215 /* Chunk crosses buffer boundary. */
216 memcpy (dst, p, u32BytesTillBoundary);
217 memcpy (&pVbvaMemory->au8RingBuffer[0], (uint8_t *)p + u32BytesTillBoundary, i32Diff);
218 }
219
220 return;
221}
222
223static BOOL vboxHwBufferWrite (PPDEV ppdev, const void *p, uint32_t cb)
224{
225 VBVAMEMORY *pVbvaMemory;
226 VBVARECORD *pRecord;
227 uint32_t cbHwBufferAvail;
228
229 uint32_t cbWritten = 0;
230
231 VBVA_ASSERT(ppdev);
232
233 if (ppdev->fHwBufferOverflow)
234 {
235 return FALSE;
236 }
237
238 pVbvaMemory = ppdev->vbva.pVbvaMemory;
239 VBVA_ASSERT (pVbvaMemory->indexRecordFirst != pVbvaMemory->indexRecordFree);
240
241 pRecord = ppdev->pRecord;
242 VBVA_ASSERT (pRecord && (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL));
243
244 DISPDBG((1, "VW %d\n", cb));
245
246 cbHwBufferAvail = vboxHwBufferAvail (pVbvaMemory);
247
248 while (cb > 0)
249 {
250 uint32_t cbChunk = cb;
251
252// 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));
253
254 if (cbChunk >= cbHwBufferAvail)
255 {
256 DISPDBG((1, "VBoxDisp::vboxHwBufferWrite 1) avail %d, chunk %d\n", cbHwBufferAvail, cbChunk));
257
258 vboxHwBufferFlush (ppdev);
259
260 cbHwBufferAvail = vboxHwBufferAvail (pVbvaMemory);
261
262 if (cbChunk >= cbHwBufferAvail)
263 {
264 DISPDBG((1, "VBoxDisp::vboxHwBufferWrite: no place for %d bytes. Only %d bytes available after flush. Going to partial writes.\n", cb, cbHwBufferAvail));
265
266 if (cbHwBufferAvail <= VBVA_RING_BUFFER_THRESHOLD)
267 {
268 DISPDBG((1, "VBoxDisp::vboxHwBufferWrite: Buffer overflow!!!\n"));
269 ppdev->fHwBufferOverflow = TRUE;
270 VBVA_ASSERT(FALSE);
271 return FALSE;
272 }
273
274 cbChunk = cbHwBufferAvail - VBVA_RING_BUFFER_THRESHOLD;
275 }
276 }
277
278 VBVA_ASSERT(cbChunk <= cb);
279 VBVA_ASSERT(cbChunk <= vboxHwBufferAvail (pVbvaMemory));
280
281 vboxHwBufferPlaceDataAt (ppdev, (uint8_t *)p + cbWritten, cbChunk, pVbvaMemory->off32Free);
282
283 pVbvaMemory->off32Free = (pVbvaMemory->off32Free + cbChunk) % VBVA_RING_BUFFER_SIZE;
284 pRecord->cbRecord += cbChunk;
285 cbHwBufferAvail -= cbChunk;
286
287 cb -= cbChunk;
288 cbWritten += cbChunk;
289 }
290
291 return TRUE;
292}
293
294/*
295 * Public writer to hardware buffer.
296 */
297BOOL vboxWrite (PPDEV ppdev, const void *pv, uint32_t cb)
298{
299 return vboxHwBufferWrite (ppdev, pv, cb);
300}
301
302BOOL vboxOrderSupported (PPDEV ppdev, unsigned code)
303{
304 VBVAMEMORY *pVbvaMemory;
305
306 pVbvaMemory = ppdev->vbva.pVbvaMemory;
307
308 if (pVbvaMemory->fu32ModeFlags & VBVA_F_MODE_VRDP_ORDER_MASK)
309 {
310 /* Order masking enabled. */
311 if (pVbvaMemory->fu32SupportedOrders & (1 << code))
312 {
313 return TRUE;
314 }
315 }
316
317 return FALSE;
318}
319
320void VBoxProcessDisplayInfo(PPDEV ppdev)
321{
322 DWORD returnedDataLength;
323
324 DISPDBG((1, "Process: %d,%d\n", ppdev->ptlDevOrg.x, ppdev->ptlDevOrg.y));
325
326 EngDeviceIoControl(ppdev->hDriver,
327 IOCTL_VIDEO_INTERPRET_DISPLAY_MEMORY,
328 NULL,
329 0,
330 NULL,
331 0,
332 &returnedDataLength);
333}
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