VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxVideo/VBVABase.cpp@ 35263

Last change on this file since 35263 was 34686, checked in by vboxsync, 14 years ago

Additions/common/VBoxVideo and Additions/WINNT/Graphics: modesetting clean-up

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.8 KB
Line 
1/* $Id: VBVABase.cpp 34686 2010-12-03 11:06:34Z vboxsync $ */
2/** @file
3 * VirtualBox Video driver, common code - VBVA initialisation and helper
4 * functions.
5 */
6
7/*
8 * Copyright (C) 2006-2010 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19#include <VBox/VBoxVideoGuest.h>
20#include <VBox/VBoxVideo.h>
21#include <VBox/err.h>
22#include <VBox/log.h>
23#include <iprt/assert.h>
24
25#include <string.h>
26
27/*
28 * There is a hardware ring buffer in the graphics device video RAM, formerly
29 * in the VBox VMMDev PCI memory space.
30 * All graphics commands go there serialized by VBoxVBVABufferBeginUpdate.
31 * and vboxHwBufferEndUpdate.
32 *
33 * off32Free is writing position. off32Data is reading position.
34 * off32Free == off32Data means buffer is empty.
35 * There must be always gap between off32Data and off32Free when data
36 * are in the buffer.
37 * Guest only changes off32Free, host changes off32Data.
38 */
39
40/* Forward declarations of internal functions. */
41static void vboxHwBufferFlush(PHGSMIGUESTCOMMANDCONTEXT pCtx);
42static void vboxHwBufferPlaceDataAt(PVBVABUFFERCONTEXT pCtx, const void *p,
43 uint32_t cb, uint32_t offset);
44static bool vboxHwBufferWrite(PVBVABUFFERCONTEXT pCtx,
45 PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
46 const void *p, uint32_t cb);
47
48
49static bool vboxVBVAInformHost(PVBVABUFFERCONTEXT pCtx,
50 PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
51 int32_t cScreen, bool bEnable)
52{
53 bool bRc = false;
54
55#if 0 /* All callers check this */
56 if (ppdev->bHGSMISupported)
57#endif
58 {
59 void *p = VBoxHGSMIBufferAlloc(pHGSMICtx,
60 sizeof (VBVAENABLE_EX),
61 HGSMI_CH_VBVA,
62 VBVA_ENABLE);
63 if (!p)
64 {
65 LogFunc(("HGSMIHeapAlloc failed\n"));
66 }
67 else
68 {
69 VBVAENABLE_EX *pEnable = (VBVAENABLE_EX *)p;
70
71 pEnable->Base.u32Flags = bEnable? VBVA_F_ENABLE: VBVA_F_DISABLE;
72 pEnable->Base.u32Offset = pCtx->offVRAMBuffer;
73 pEnable->Base.i32Result = VERR_NOT_SUPPORTED;
74 if (cScreen >= 0)
75 {
76 pEnable->Base.u32Flags |= VBVA_F_EXTENDED | VBVA_F_ABSOFFSET;
77 pEnable->u32ScreenId = cScreen;
78 }
79
80 VBoxHGSMIBufferSubmit(pHGSMICtx, p);
81
82 if (bEnable)
83 {
84 bRc = RT_SUCCESS(pEnable->Base.i32Result);
85 }
86 else
87 {
88 bRc = true;
89 }
90
91 VBoxHGSMIBufferFree(pHGSMICtx, p);
92 }
93 }
94
95 return bRc;
96}
97
98/*
99 * Public hardware buffer methods.
100 */
101RTDECL(bool) VBoxVBVAEnable(PVBVABUFFERCONTEXT pCtx,
102 PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
103 VBVABUFFER *pVBVA, int32_t cScreen)
104{
105 bool bRc = false;
106
107 LogFlowFunc(("pVBVA %p\n", pVBVA));
108
109#if 0 /* All callers check this */
110 if (ppdev->bHGSMISupported)
111#endif
112 {
113 LogFunc(("pVBVA %p vbva off 0x%x\n", pVBVA, pCtx->offVRAMBuffer));
114
115 pVBVA->hostFlags.u32HostEvents = 0;
116 pVBVA->hostFlags.u32SupportedOrders = 0;
117 pVBVA->off32Data = 0;
118 pVBVA->off32Free = 0;
119 memset(pVBVA->aRecords, 0, sizeof (pVBVA->aRecords));
120 pVBVA->indexRecordFirst = 0;
121 pVBVA->indexRecordFree = 0;
122 pVBVA->cbPartialWriteThreshold = 256;
123 pVBVA->cbData = pCtx->cbBuffer - sizeof (VBVABUFFER) + sizeof (pVBVA->au8Data);
124
125 pCtx->fHwBufferOverflow = false;
126 pCtx->pRecord = NULL;
127 pCtx->pVBVA = pVBVA;
128
129 bRc = vboxVBVAInformHost(pCtx, pHGSMICtx, cScreen, true);
130 }
131
132 if (!bRc)
133 {
134 VBoxVBVADisable(pCtx, pHGSMICtx, cScreen);
135 }
136
137 return bRc;
138}
139
140RTDECL(void) VBoxVBVADisable(PVBVABUFFERCONTEXT pCtx,
141 PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
142 int32_t cScreen)
143{
144 LogFlowFunc(("\n"));
145
146 pCtx->fHwBufferOverflow = false;
147 pCtx->pRecord = NULL;
148 pCtx->pVBVA = NULL;
149
150 vboxVBVAInformHost(pCtx, pHGSMICtx, cScreen, false);
151
152 return;
153}
154
155RTDECL(bool) VBoxVBVABufferBeginUpdate(PVBVABUFFERCONTEXT pCtx,
156 PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx)
157{
158 bool bRc = false;
159
160 // LogFunc(("flags = 0x%08X\n", pCtx->pVBVA? pCtx->pVBVA->u32HostEvents: -1));
161
162 if ( pCtx->pVBVA
163 && (pCtx->pVBVA->hostFlags.u32HostEvents & VBVA_F_MODE_ENABLED))
164 {
165 uint32_t indexRecordNext;
166
167 Assert(!pCtx->fHwBufferOverflow);
168 Assert(pCtx->pRecord == NULL);
169
170 indexRecordNext = (pCtx->pVBVA->indexRecordFree + 1) % VBVA_MAX_RECORDS;
171
172 if (indexRecordNext == pCtx->pVBVA->indexRecordFirst)
173 {
174 /* All slots in the records queue are used. */
175 vboxHwBufferFlush (pHGSMICtx);
176 }
177
178 if (indexRecordNext == pCtx->pVBVA->indexRecordFirst)
179 {
180 /* Even after flush there is no place. Fail the request. */
181 LogFunc(("no space in the queue of records!!! first %d, last %d\n",
182 pCtx->pVBVA->indexRecordFirst, pCtx->pVBVA->indexRecordFree));
183 }
184 else
185 {
186 /* Initialize the record. */
187 VBVARECORD *pRecord = &pCtx->pVBVA->aRecords[pCtx->pVBVA->indexRecordFree];
188
189 pRecord->cbRecord = VBVA_F_RECORD_PARTIAL;
190
191 pCtx->pVBVA->indexRecordFree = indexRecordNext;
192
193 // LogFunc(("indexRecordNext = %d\n", indexRecordNext));
194
195 /* Remember which record we are using. */
196 pCtx->pRecord = pRecord;
197
198 bRc = true;
199 }
200 }
201
202 return bRc;
203}
204
205RTDECL(void) VBoxVBVABufferEndUpdate(PVBVABUFFERCONTEXT pCtx)
206{
207 VBVARECORD *pRecord;
208
209 // LogFunc(("\n"));
210
211 Assert(pCtx->pVBVA);
212
213 pRecord = pCtx->pRecord;
214 Assert(pRecord && (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL));
215
216 /* Mark the record completed. */
217 pRecord->cbRecord &= ~VBVA_F_RECORD_PARTIAL;
218
219 pCtx->fHwBufferOverflow = false;
220 pCtx->pRecord = NULL;
221
222 return;
223}
224
225/*
226 * Private operations.
227 */
228static uint32_t vboxHwBufferAvail (const VBVABUFFER *pVBVA)
229{
230 int32_t i32Diff = pVBVA->off32Data - pVBVA->off32Free;
231
232 return i32Diff > 0? i32Diff: pVBVA->cbData + i32Diff;
233}
234
235static void vboxHwBufferFlush(PHGSMIGUESTCOMMANDCONTEXT pCtx)
236{
237 /* Issue the flush command. */
238 void *p = VBoxHGSMIBufferAlloc(pCtx,
239 sizeof (VBVAFLUSH),
240 HGSMI_CH_VBVA,
241 VBVA_FLUSH);
242 if (!p)
243 {
244 LogFunc(("HGSMIHeapAlloc failed\n"));
245 }
246 else
247 {
248 VBVAFLUSH *pFlush = (VBVAFLUSH *)p;
249
250 pFlush->u32Reserved = 0;
251
252 VBoxHGSMIBufferSubmit(pCtx, p);
253
254 VBoxHGSMIBufferSubmit(pCtx, p);
255 }
256
257 return;
258}
259
260static void vboxHwBufferPlaceDataAt(PVBVABUFFERCONTEXT pCtx, const void *p,
261 uint32_t cb, uint32_t offset)
262{
263 VBVABUFFER *pVBVA = pCtx->pVBVA;
264 uint32_t u32BytesTillBoundary = pVBVA->cbData - offset;
265 uint8_t *dst = &pVBVA->au8Data[offset];
266 int32_t i32Diff = cb - u32BytesTillBoundary;
267
268 if (i32Diff <= 0)
269 {
270 /* Chunk will not cross buffer boundary. */
271 memcpy (dst, p, cb);
272 }
273 else
274 {
275 /* Chunk crosses buffer boundary. */
276 memcpy (dst, p, u32BytesTillBoundary);
277 memcpy (&pVBVA->au8Data[0], (uint8_t *)p + u32BytesTillBoundary, i32Diff);
278 }
279
280 return;
281}
282
283static bool vboxHwBufferWrite(PVBVABUFFERCONTEXT pCtx,
284 PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
285 const void *p, uint32_t cb)
286{
287 VBVARECORD *pRecord;
288 uint32_t cbHwBufferAvail;
289
290 uint32_t cbWritten = 0;
291
292 VBVABUFFER *pVBVA = pCtx->pVBVA;
293 Assert(pVBVA);
294
295 if (!pVBVA || pCtx->fHwBufferOverflow)
296 {
297 return false;
298 }
299
300 Assert(pVBVA->indexRecordFirst != pVBVA->indexRecordFree);
301
302 pRecord = pCtx->pRecord;
303 Assert(pRecord && (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL));
304
305 LogFunc(("%d\n", cb));
306
307 cbHwBufferAvail = vboxHwBufferAvail (pVBVA);
308
309 while (cb > 0)
310 {
311 uint32_t cbChunk = cb;
312
313 // LogFunc(("pVBVA->off32Free %d, pRecord->cbRecord 0x%08X, cbHwBufferAvail %d, cb %d, cbWritten %d\n",
314 // pVBVA->off32Free, pRecord->cbRecord, cbHwBufferAvail, cb, cbWritten));
315
316 if (cbChunk >= cbHwBufferAvail)
317 {
318 LogFunc(("1) avail %d, chunk %d\n", cbHwBufferAvail, cbChunk));
319
320 vboxHwBufferFlush (pHGSMICtx);
321
322 cbHwBufferAvail = vboxHwBufferAvail (pVBVA);
323
324 if (cbChunk >= cbHwBufferAvail)
325 {
326 LogFunc(("no place for %d bytes. Only %d bytes available after flush. Going to partial writes.\n",
327 cb, cbHwBufferAvail));
328
329 if (cbHwBufferAvail <= pVBVA->cbPartialWriteThreshold)
330 {
331 LogFunc(("Buffer overflow!!!\n"));
332 pCtx->fHwBufferOverflow = true;
333 Assert(false);
334 return false;
335 }
336
337 cbChunk = cbHwBufferAvail - pVBVA->cbPartialWriteThreshold;
338 }
339 }
340
341 Assert(cbChunk <= cb);
342 Assert(cbChunk <= vboxHwBufferAvail (pVBVA));
343
344 vboxHwBufferPlaceDataAt (pCtx, (uint8_t *)p + cbWritten, cbChunk, pVBVA->off32Free);
345
346 pVBVA->off32Free = (pVBVA->off32Free + cbChunk) % pVBVA->cbData;
347 pRecord->cbRecord += cbChunk;
348 cbHwBufferAvail -= cbChunk;
349
350 cb -= cbChunk;
351 cbWritten += cbChunk;
352 }
353
354 return true;
355}
356
357/*
358 * Public writer to the hardware buffer.
359 */
360RTDECL(bool) VBoxVBVAWrite(PVBVABUFFERCONTEXT pCtx,
361 PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
362 const void *pv, uint32_t cb)
363{
364 return vboxHwBufferWrite (pCtx, pHGSMICtx, pv, cb);
365}
366
367RTDECL(bool) VBoxVBVAOrderSupported(PVBVABUFFERCONTEXT pCtx, unsigned code)
368{
369 VBVABUFFER *pVBVA = pCtx->pVBVA;
370
371 if (!pVBVA)
372 {
373 return false;
374 }
375
376 if (pVBVA->hostFlags.u32SupportedOrders & (1 << code))
377 {
378 return true;
379 }
380
381 return false;
382}
383
384RTDECL(void) VBoxVBVASetupBufferContext(PVBVABUFFERCONTEXT pCtx,
385 uint32_t offVRAMBuffer,
386 uint32_t cbBuffer)
387{
388 pCtx->offVRAMBuffer = offVRAMBuffer;
389 pCtx->cbBuffer = cbBuffer;
390}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use