VirtualBox

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

最後變更 在這個檔案從66544是 66544,由 vboxsync 提交於 8 年 前

bugref:8524: Additions/linux: play nicely with distribution-installed Additions
Change header of files which are expected to end up in the Linux kernel to the MIT licence to simplify life for people wanting to port vboxvideo to other kernels and to simplify synchronising changes back to VirtualBox. Update author information in files which have it, but do not add it to files which do not.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 11.4 KB
 
1/* $Id: VBVABase.cpp 66544 2017-04-12 17:02:30Z vboxsync $ */
2/** @file
3 * VirtualBox Video driver, common code - VBVA initialisation and helper
4 * functions.
5 */
6
7/*
8 * Copyright (C) 2006-2017 Oracle Corporation
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a
11 * copy of this software and associated documentation files (the "Software"),
12 * to deal in the Software without restriction, including without limitation
13 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 * and/or sell copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
24 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 * OTHER DEALINGS IN THE SOFTWARE.
27 */
28
29#include <VBoxVideoGuest.h>
30#include <VBoxVideoIPRT.h>
31
32/*
33 * There is a hardware ring buffer in the graphics device video RAM, formerly
34 * in the VBox VMMDev PCI memory space.
35 * All graphics commands go there serialized by VBoxVBVABufferBeginUpdate.
36 * and vboxHwBufferEndUpdate.
37 *
38 * off32Free is writing position. off32Data is reading position.
39 * off32Free == off32Data means buffer is empty.
40 * There must be always gap between off32Data and off32Free when data
41 * are in the buffer.
42 * Guest only changes off32Free, host changes off32Data.
43 */
44
45/* Forward declarations of internal functions. */
46static void vboxHwBufferFlush(PHGSMIGUESTCOMMANDCONTEXT pCtx);
47static void vboxHwBufferPlaceDataAt(PVBVABUFFERCONTEXT pCtx, const void *p,
48 uint32_t cb, uint32_t offset);
49static bool vboxHwBufferWrite(PVBVABUFFERCONTEXT pCtx,
50 PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
51 const void *p, uint32_t cb);
52
53
54static bool vboxVBVAInformHost(PVBVABUFFERCONTEXT pCtx,
55 PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
56 int32_t cScreen, bool bEnable)
57{
58 bool bRc = false;
59
60#if 0 /* All callers check this */
61 if (ppdev->bHGSMISupported)
62#endif
63 {
64 void *p = VBoxHGSMIBufferAlloc(pHGSMICtx,
65 sizeof (VBVAENABLE_EX),
66 HGSMI_CH_VBVA,
67 VBVA_ENABLE);
68 if (!p)
69 {
70 // LogFunc(("HGSMIHeapAlloc failed\n"));
71 }
72 else
73 {
74 VBVAENABLE_EX *pEnable = (VBVAENABLE_EX *)p;
75
76 pEnable->Base.u32Flags = bEnable? VBVA_F_ENABLE: VBVA_F_DISABLE;
77 pEnable->Base.u32Offset = pCtx->offVRAMBuffer;
78 pEnable->Base.i32Result = VERR_NOT_SUPPORTED;
79 if (cScreen >= 0)
80 {
81 pEnable->Base.u32Flags |= VBVA_F_EXTENDED | VBVA_F_ABSOFFSET;
82 pEnable->u32ScreenId = cScreen;
83 }
84
85 VBoxHGSMIBufferSubmit(pHGSMICtx, p);
86
87 if (bEnable)
88 {
89 bRc = RT_SUCCESS(pEnable->Base.i32Result);
90 }
91 else
92 {
93 bRc = true;
94 }
95
96 VBoxHGSMIBufferFree(pHGSMICtx, p);
97 }
98 }
99
100 return bRc;
101}
102
103/*
104 * Public hardware buffer methods.
105 */
106DECLHIDDEN(bool) VBoxVBVAEnable(PVBVABUFFERCONTEXT pCtx,
107 PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
108 VBVABUFFER *pVBVA, int32_t cScreen)
109{
110 bool bRc = false;
111
112 // LogFlowFunc(("pVBVA %p\n", pVBVA));
113
114#if 0 /* All callers check this */
115 if (ppdev->bHGSMISupported)
116#endif
117 {
118 // LogFunc(("pVBVA %p vbva off 0x%x\n", pVBVA, pCtx->offVRAMBuffer));
119
120 pVBVA->hostFlags.u32HostEvents = 0;
121 pVBVA->hostFlags.u32SupportedOrders = 0;
122 pVBVA->off32Data = 0;
123 pVBVA->off32Free = 0;
124 memset(pVBVA->aRecords, 0, sizeof (pVBVA->aRecords));
125 pVBVA->indexRecordFirst = 0;
126 pVBVA->indexRecordFree = 0;
127 pVBVA->cbPartialWriteThreshold = 256;
128 pVBVA->cbData = pCtx->cbBuffer - sizeof (VBVABUFFER) + sizeof (pVBVA->au8Data);
129
130 pCtx->fHwBufferOverflow = false;
131 pCtx->pRecord = NULL;
132 pCtx->pVBVA = pVBVA;
133
134 bRc = vboxVBVAInformHost(pCtx, pHGSMICtx, cScreen, true);
135 }
136
137 if (!bRc)
138 {
139 VBoxVBVADisable(pCtx, pHGSMICtx, cScreen);
140 }
141
142 return bRc;
143}
144
145DECLHIDDEN(void) VBoxVBVADisable(PVBVABUFFERCONTEXT pCtx,
146 PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
147 int32_t cScreen)
148{
149 // LogFlowFunc(("\n"));
150
151 pCtx->fHwBufferOverflow = false;
152 pCtx->pRecord = NULL;
153 pCtx->pVBVA = NULL;
154
155 vboxVBVAInformHost(pCtx, pHGSMICtx, cScreen, false);
156
157 return;
158}
159
160DECLHIDDEN(bool) VBoxVBVABufferBeginUpdate(PVBVABUFFERCONTEXT pCtx,
161 PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx)
162{
163 bool bRc = false;
164
165 // LogFunc(("flags = 0x%08X\n", pCtx->pVBVA? pCtx->pVBVA->u32HostEvents: -1));
166
167 if ( pCtx->pVBVA
168 && (pCtx->pVBVA->hostFlags.u32HostEvents & VBVA_F_MODE_ENABLED))
169 {
170 uint32_t indexRecordNext;
171
172 Assert(!pCtx->fHwBufferOverflow);
173 Assert(pCtx->pRecord == NULL);
174
175 indexRecordNext = (pCtx->pVBVA->indexRecordFree + 1) % VBVA_MAX_RECORDS;
176
177 if (indexRecordNext == pCtx->pVBVA->indexRecordFirst)
178 {
179 /* All slots in the records queue are used. */
180 vboxHwBufferFlush (pHGSMICtx);
181 }
182
183 if (indexRecordNext == pCtx->pVBVA->indexRecordFirst)
184 {
185 /* Even after flush there is no place. Fail the request. */
186 // LogFunc(("no space in the queue of records!!! first %d, last %d\n",
187 // pCtx->pVBVA->indexRecordFirst, pCtx->pVBVA->indexRecordFree));
188 }
189 else
190 {
191 /* Initialize the record. */
192 VBVARECORD *pRecord = &pCtx->pVBVA->aRecords[pCtx->pVBVA->indexRecordFree];
193
194 pRecord->cbRecord = VBVA_F_RECORD_PARTIAL;
195
196 pCtx->pVBVA->indexRecordFree = indexRecordNext;
197
198 // LogFunc(("indexRecordNext = %d\n", indexRecordNext));
199
200 /* Remember which record we are using. */
201 pCtx->pRecord = pRecord;
202
203 bRc = true;
204 }
205 }
206
207 return bRc;
208}
209
210DECLHIDDEN(void) VBoxVBVABufferEndUpdate(PVBVABUFFERCONTEXT pCtx)
211{
212 VBVARECORD *pRecord;
213
214 // LogFunc(("\n"));
215
216 Assert(pCtx->pVBVA);
217
218 pRecord = pCtx->pRecord;
219 Assert(pRecord && (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL));
220
221 /* Mark the record completed. */
222 pRecord->cbRecord &= ~VBVA_F_RECORD_PARTIAL;
223
224 pCtx->fHwBufferOverflow = false;
225 pCtx->pRecord = NULL;
226
227 return;
228}
229
230/*
231 * Private operations.
232 */
233static uint32_t vboxHwBufferAvail (const VBVABUFFER *pVBVA)
234{
235 int32_t i32Diff = pVBVA->off32Data - pVBVA->off32Free;
236
237 return i32Diff > 0? i32Diff: pVBVA->cbData + i32Diff;
238}
239
240static void vboxHwBufferFlush(PHGSMIGUESTCOMMANDCONTEXT pCtx)
241{
242 /* Issue the flush command. */
243 void *p = VBoxHGSMIBufferAlloc(pCtx,
244 sizeof (VBVAFLUSH),
245 HGSMI_CH_VBVA,
246 VBVA_FLUSH);
247 if (!p)
248 {
249 // LogFunc(("HGSMIHeapAlloc failed\n"));
250 }
251 else
252 {
253 VBVAFLUSH *pFlush = (VBVAFLUSH *)p;
254
255 pFlush->u32Reserved = 0;
256
257 VBoxHGSMIBufferSubmit(pCtx, p);
258
259 VBoxHGSMIBufferFree(pCtx, p);
260 }
261
262 return;
263}
264
265static void vboxHwBufferPlaceDataAt(PVBVABUFFERCONTEXT pCtx, const void *p,
266 uint32_t cb, uint32_t offset)
267{
268 VBVABUFFER *pVBVA = pCtx->pVBVA;
269 uint32_t u32BytesTillBoundary = pVBVA->cbData - offset;
270 uint8_t *dst = &pVBVA->au8Data[offset];
271 int32_t i32Diff = cb - u32BytesTillBoundary;
272
273 if (i32Diff <= 0)
274 {
275 /* Chunk will not cross buffer boundary. */
276 memcpy (dst, p, cb);
277 }
278 else
279 {
280 /* Chunk crosses buffer boundary. */
281 memcpy (dst, p, u32BytesTillBoundary);
282 memcpy (&pVBVA->au8Data[0], (uint8_t *)p + u32BytesTillBoundary, i32Diff);
283 }
284
285 return;
286}
287
288static bool vboxHwBufferWrite(PVBVABUFFERCONTEXT pCtx,
289 PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
290 const void *p, uint32_t cb)
291{
292 VBVARECORD *pRecord;
293 uint32_t cbHwBufferAvail;
294
295 uint32_t cbWritten = 0;
296
297 VBVABUFFER *pVBVA = pCtx->pVBVA;
298 Assert(pVBVA);
299
300 if (!pVBVA || pCtx->fHwBufferOverflow)
301 {
302 return false;
303 }
304
305 Assert(pVBVA->indexRecordFirst != pVBVA->indexRecordFree);
306
307 pRecord = pCtx->pRecord;
308 Assert(pRecord && (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL));
309
310 // LogFunc(("%d\n", cb));
311
312 cbHwBufferAvail = vboxHwBufferAvail (pVBVA);
313
314 while (cb > 0)
315 {
316 uint32_t cbChunk = cb;
317
318 // LogFunc(("pVBVA->off32Free %d, pRecord->cbRecord 0x%08X, cbHwBufferAvail %d, cb %d, cbWritten %d\n",
319 // pVBVA->off32Free, pRecord->cbRecord, cbHwBufferAvail, cb, cbWritten));
320
321 if (cbChunk >= cbHwBufferAvail)
322 {
323 // LogFunc(("1) avail %d, chunk %d\n", cbHwBufferAvail, cbChunk));
324
325 vboxHwBufferFlush (pHGSMICtx);
326
327 cbHwBufferAvail = vboxHwBufferAvail (pVBVA);
328
329 if (cbChunk >= cbHwBufferAvail)
330 {
331 // LogFunc(("no place for %d bytes. Only %d bytes available after flush. Going to partial writes.\n",
332 // cb, cbHwBufferAvail));
333
334 if (cbHwBufferAvail <= pVBVA->cbPartialWriteThreshold)
335 {
336 // LogFunc(("Buffer overflow!!!\n"));
337 pCtx->fHwBufferOverflow = true;
338 Assert(false);
339 return false;
340 }
341
342 cbChunk = cbHwBufferAvail - pVBVA->cbPartialWriteThreshold;
343 }
344 }
345
346 Assert(cbChunk <= cb);
347 Assert(cbChunk <= vboxHwBufferAvail (pVBVA));
348
349 vboxHwBufferPlaceDataAt (pCtx, (uint8_t *)p + cbWritten, cbChunk, pVBVA->off32Free);
350
351 pVBVA->off32Free = (pVBVA->off32Free + cbChunk) % pVBVA->cbData;
352 pRecord->cbRecord += cbChunk;
353 cbHwBufferAvail -= cbChunk;
354
355 cb -= cbChunk;
356 cbWritten += cbChunk;
357 }
358
359 return true;
360}
361
362/*
363 * Public writer to the hardware buffer.
364 */
365DECLHIDDEN(bool) VBoxVBVAWrite(PVBVABUFFERCONTEXT pCtx,
366 PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
367 const void *pv, uint32_t cb)
368{
369 return vboxHwBufferWrite (pCtx, pHGSMICtx, pv, cb);
370}
371
372DECLHIDDEN(bool) VBoxVBVAOrderSupported(PVBVABUFFERCONTEXT pCtx, unsigned code)
373{
374 VBVABUFFER *pVBVA = pCtx->pVBVA;
375
376 if (!pVBVA)
377 {
378 return false;
379 }
380
381 if (pVBVA->hostFlags.u32SupportedOrders & (1 << code))
382 {
383 return true;
384 }
385
386 return false;
387}
388
389DECLHIDDEN(void) VBoxVBVASetupBufferContext(PVBVABUFFERCONTEXT pCtx,
390 uint32_t offVRAMBuffer,
391 uint32_t cbBuffer)
392{
393 pCtx->offVRAMBuffer = offVRAMBuffer;
394 pCtx->cbBuffer = cbBuffer;
395}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette