VirtualBox

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

Last change on this file since 2705 was 1, checked in by vboxsync, 55 years ago

import

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.4 KB
Line 
1/** @file
2 *
3 * VBoxGuest -- VirtualBox Win 2000/XP guest display driver
4 *
5 * VBox support functions.
6 *
7 * Copyright (C) 2006 InnoTek Systemberatung 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 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 *
21 */
22
23#include "driver.h"
24
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/*
47 * Public hardware buffer methods.
48 */
49BOOL vboxVbvaEnable (PPDEV ppdev)
50{
51 BOOL bRc = FALSE;
52
53 ULONG returnedDataLength;
54 ULONG ulEnable = TRUE;
55
56 DISPDBG((1, "VBoxDisp::vboxVbvaEnable called\n"));
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 if (!ppdev->hsemHwBuffer)
74 {
75 ppdev->hsemHwBuffer = EngCreateSemaphore ();
76 }
77
78 if (ppdev->hsemHwBuffer)
79 {
80 ppdev->fHwBufferOverflow = FALSE;
81 ppdev->pRecord = NULL;
82
83 /* All have been initialized. */
84 bRc = TRUE;
85 }
86 else
87 {
88 DISPDBG((1, "VBoxDisp::vboxVbvaEnable failed to create semaphore!!!\n"));
89 }
90 }
91 }
92
93 if (!bRc)
94 {
95 vboxVbvaDisable (ppdev);
96 }
97
98 return bRc;
99}
100
101void vboxVbvaDisable (PPDEV ppdev)
102{
103 DISPDBG((1, "VBoxDisp::vbvaDisable called.\n"));
104
105 RtlZeroMemory (&ppdev->vbva, sizeof (ppdev->vbva));
106
107 if (ppdev->hsemHwBuffer)
108 {
109 EngDeleteSemaphore (ppdev->hsemHwBuffer);
110 ppdev->hsemHwBuffer = NULL;
111 }
112
113 ppdev->fHwBufferOverflow = FALSE;
114 ppdev->pRecord = NULL;
115
116 return;
117}
118
119BOOL vboxHwBufferBeginUpdate (PPDEV ppdev)
120{
121 BOOL bRc = FALSE;
122
123 VBVAMEMORY *pVbvaMemory = ppdev->vbva.pVbvaMemory;
124
125 DISPDBG((1, "VBoxDisp::vboxHwBufferBeginUpdate called flags = 0x%08X\n", pVbvaMemory? pVbvaMemory->fu32ModeFlags: -1));
126
127 if ( pVbvaMemory
128 && (pVbvaMemory->fu32ModeFlags & VBVA_F_MODE_ENABLED))
129 {
130 uint32_t indexRecordNext;
131
132 EngAcquireSemaphore (ppdev->hsemHwBuffer);
133
134 VBVA_ASSERT (!ppdev->fHwBufferOverflow);
135 VBVA_ASSERT (ppdev->pRecord == NULL);
136
137 indexRecordNext = (pVbvaMemory->indexRecordFree + 1) % VBVA_MAX_RECORDS;
138
139 if (indexRecordNext == pVbvaMemory->indexRecordFirst)
140 {
141 /* All slots in the records queue are used. */
142 vboxHwBufferFlush (ppdev);
143 }
144
145 if (indexRecordNext == pVbvaMemory->indexRecordFirst)
146 {
147 /* Even after flush there is no place. Fail the request. */
148 DISPDBG((1, "VBoxDisp::vboxHwBufferBeginUpdate no space in the queue of records!!! first %d, last %d\n",
149 pVbvaMemory->indexRecordFirst, pVbvaMemory->indexRecordFree));
150 EngReleaseSemaphore (ppdev->hsemHwBuffer);
151 }
152 else
153 {
154 /* Initialize the record. */
155 VBVARECORD *pRecord = &pVbvaMemory->aRecords[pVbvaMemory->indexRecordFree];
156
157 pRecord->cbRecord = VBVA_F_RECORD_PARTIAL;
158
159 pVbvaMemory->indexRecordFree = indexRecordNext;
160
161 DISPDBG((1, "VBoxDisp::vboxHwBufferBeginUpdate indexRecordNext = %d\n", indexRecordNext));
162
163 /* Remember which record we are using. */
164 ppdev->pRecord = pRecord;
165
166 bRc = TRUE;
167 }
168 }
169
170 return bRc;
171}
172
173void vboxHwBufferEndUpdate (PPDEV ppdev)
174{
175 VBVAMEMORY *pVbvaMemory;
176 VBVARECORD *pRecord;
177
178 DISPDBG((1, "VBoxDisp::vboxHwBufferEndUpdate called\n"));
179
180 pVbvaMemory = ppdev->vbva.pVbvaMemory;
181 VBVA_ASSERT(pVbvaMemory);
182
183 pRecord = ppdev->pRecord;
184 VBVA_ASSERT (pRecord && (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL));
185
186 /* Mark the record completed. */
187 pRecord->cbRecord &= ~VBVA_F_RECORD_PARTIAL;
188
189 ppdev->fHwBufferOverflow = FALSE;
190 ppdev->pRecord = NULL;
191
192 EngReleaseSemaphore (ppdev->hsemHwBuffer);
193
194 return;
195}
196
197/*
198 * Private operations.
199 */
200static uint32_t vboxHwBufferAvail (VBVAMEMORY *pVbvaMemory)
201{
202 int32_t i32Diff = pVbvaMemory->off32Data - pVbvaMemory->off32Free;
203
204 return i32Diff > 0? i32Diff: VBVA_RING_BUFFER_SIZE + i32Diff;
205}
206
207static void vboxHwBufferFlush (PPDEV ppdev)
208{
209 VBVAMEMORY *pVbvaMemory = ppdev->vbva.pVbvaMemory;
210
211 VBVA_ASSERT (pVbvaMemory);
212
213 ppdev->vbva.pfnFlush (ppdev->vbva.pvFlush);
214
215 return;
216}
217
218static void vboxHwBufferPlaceDataAt (PPDEV ppdev, void *p, uint32_t cb, uint32_t offset)
219{
220 VBVAMEMORY *pVbvaMemory = ppdev->vbva.pVbvaMemory;
221
222 uint32_t u32BytesTillBoundary = VBVA_RING_BUFFER_SIZE - offset;
223 uint8_t *dst = &pVbvaMemory->au8RingBuffer[offset];
224 int32_t i32Diff = cb - u32BytesTillBoundary;
225
226 if (i32Diff <= 0)
227 {
228 /* Chunk will not cross buffer boundary. */
229 memcpy (dst, p, cb);
230 }
231 else
232 {
233 /* Chunk crosses buffer boundary. */
234 memcpy (dst, p, u32BytesTillBoundary);
235 memcpy (&pVbvaMemory->au8RingBuffer[0], (uint8_t *)p + u32BytesTillBoundary, i32Diff);
236 }
237
238 return;
239}
240
241static BOOL vboxHwBufferWrite (PPDEV ppdev, const void *p, uint32_t cb)
242{
243 VBVAMEMORY *pVbvaMemory;
244 VBVARECORD *pRecord;
245 uint32_t cbHwBufferAvail;
246
247 uint32_t cbWritten = 0;
248
249 VBVA_ASSERT(ppdev);
250
251 if (ppdev->fHwBufferOverflow)
252 {
253 return FALSE;
254 }
255
256 pVbvaMemory = ppdev->vbva.pVbvaMemory;
257 VBVA_ASSERT (pVbvaMemory->indexRecordFirst != pVbvaMemory->indexRecordFree);
258
259 pRecord = ppdev->pRecord;
260 VBVA_ASSERT (pRecord && (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL));
261
262 DISPDBG((1, "VW %d\n", cb));
263
264 cbHwBufferAvail = vboxHwBufferAvail (pVbvaMemory);
265
266 while (cb > 0)
267 {
268 uint32_t cbChunk = cb;
269
270// 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));
271
272 if (cbChunk >= cbHwBufferAvail)
273 {
274 DISPDBG((1, "VBoxDisp::vboxHwBufferWrite 1) avail %d, chunk %d\n", cbHwBufferAvail, cbChunk));
275
276 vboxHwBufferFlush (ppdev);
277
278 cbHwBufferAvail = vboxHwBufferAvail (pVbvaMemory);
279
280 if (cbChunk >= cbHwBufferAvail)
281 {
282 DISPDBG((1, "VBoxDisp::vboxHwBufferWrite: no place for %d bytes. Only %d bytes available after flush. Going to partial writes.\n", cb, cbHwBufferAvail));
283
284 if (cbHwBufferAvail <= VBVA_RING_BUFFER_THRESHOLD)
285 {
286 DISPDBG((1, "VBoxDisp::vboxHwBufferWrite: Buffer overflow!!!\n"));
287 ppdev->fHwBufferOverflow = TRUE;
288 VBVA_ASSERT(FALSE);
289 return FALSE;
290 }
291
292 cbChunk = cbHwBufferAvail - VBVA_RING_BUFFER_THRESHOLD;
293 }
294 }
295
296 VBVA_ASSERT(cbChunk <= cb);
297 VBVA_ASSERT(cbChunk <= vboxHwBufferAvail (pVbvaMemory));
298
299 vboxHwBufferPlaceDataAt (ppdev, (uint8_t *)p + cbWritten, cbChunk, pVbvaMemory->off32Free);
300
301 pVbvaMemory->off32Free = (pVbvaMemory->off32Free + cbChunk) % VBVA_RING_BUFFER_SIZE;
302 pRecord->cbRecord += cbChunk;
303 cbHwBufferAvail -= cbChunk;
304
305 cb -= cbChunk;
306 cbWritten += cbChunk;
307 }
308
309 return TRUE;
310}
311
312/*
313 * Public writer to hardware buffer.
314 */
315BOOL vboxWrite (PPDEV ppdev, const void *pv, uint32_t cb)
316{
317 return vboxHwBufferWrite (ppdev, pv, cb);
318}
319
320BOOL vboxOrderSupported (PPDEV ppdev, unsigned code)
321{
322 VBVAMEMORY *pVbvaMemory;
323
324 pVbvaMemory = ppdev->vbva.pVbvaMemory;
325
326 if (pVbvaMemory->fu32ModeFlags & VBVA_F_MODE_VRDP_ORDER_MASK)
327 {
328 /* Order masking enabled. */
329 if (pVbvaMemory->fu32SupportedOrders & (1 << code))
330 {
331 return TRUE;
332 }
333 }
334
335 return FALSE;
336}
337
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