VirtualBox

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

Last change on this file since 69309 was 69309, checked in by vboxsync, 7 years ago

common/VBoxVideo: scm update and todo regarding syntax checking/library

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