VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/GraphicsAdapterImpl.cpp@ 105864

Last change on this file since 105864 was 105864, checked in by vboxsync, 3 months ago

Main: Added API for querying graphics features (2D Video / 3D Acceleration) of a specific graphics controller for a given platform and revamped the graphics controller attributes for 2D / 3D setters/getters to also use the new graphics features enumeration. Also, the system properties also now contain a dedicated API to query for graphics features (very basic for now, needs to be stuffed out). See SDK changelog for details. Added validation code when setting a specific graphics feature (which we never did before). bugref:10749

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.0 KB
Line 
1/* $Id: GraphicsAdapterImpl.cpp 105864 2024-08-26 18:45:15Z vboxsync $ */
2/** @file
3 * Implementation of IGraphicsAdapter in VBoxSVC.
4 */
5
6/*
7 * Copyright (C) 2004-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#define LOG_GROUP LOG_GROUP_MAIN_GRAPHICSADAPTER
29
30#include "LoggingNew.h"
31
32#include "GraphicsAdapterImpl.h"
33#include "MachineImpl.h"
34
35#include "AutoStateDep.h"
36#include "AutoCaller.h"
37
38#include <iprt/cpp/utils.h>
39
40
41/** @def MY_VECTOR_ASSIGN_ARRAY
42 * Safe way to copy an array (static + const) into a vector w/ minimal typing.
43 *
44 * @param a_rVector The destination vector reference.
45 * @param a_aSrcArray The source array to assign to the vector.
46 */
47#if RT_GNUC_PREREQ(13, 0) && !RT_GNUC_PREREQ(14, 0) && defined(VBOX_WITH_GCC_SANITIZER)
48/* Workaround for g++ 13.2 incorrectly failing on arrays with a single entry in ASAN builds.
49 This is restricted to [13.0, 14.0), assuming the issue was introduced in the 13 cycle
50 and will be fixed by the time 14 is done. If 14 doesn't fix it, extend the range
51 version by version till it is fixed. */
52# define MY_VECTOR_ASSIGN_ARRAY(a_rVector, a_aSrcArray) do { \
53 _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wstringop-overread\""); \
54 (a_rVector).assign(&a_aSrcArray[0], &a_aSrcArray[RT_ELEMENTS(a_aSrcArray)]); \
55 _Pragma("GCC diagnostic pop"); \
56 } while (0)
57#else
58# define MY_VECTOR_ASSIGN_ARRAY(a_rVector, a_aSrcArray) do { \
59 (a_rVector).assign(&a_aSrcArray[0], &a_aSrcArray[RT_ELEMENTS(a_aSrcArray)]); \
60 } while (0)
61#endif
62
63
64// constructor / destructor
65/////////////////////////////////////////////////////////////////////////////
66
67GraphicsAdapter::GraphicsAdapter() :
68 mParent(NULL)
69{}
70
71GraphicsAdapter::~GraphicsAdapter()
72{}
73
74HRESULT GraphicsAdapter::FinalConstruct()
75{
76 LogFlowThisFunc(("\n"));
77 return BaseFinalConstruct();
78}
79
80void GraphicsAdapter::FinalRelease()
81{
82 LogFlowThisFunc(("\n"));
83 uninit();
84 BaseFinalRelease();
85}
86
87// public initializer/uninitializer for internal purposes only
88/////////////////////////////////////////////////////////////////////////////
89
90/**
91 * Initializes the graphics adapter object.
92 *
93 * @param aParent Handle of the parent object.
94 */
95HRESULT GraphicsAdapter::init(Machine *aParent)
96{
97 LogFlowThisFunc(("aParent=%p\n", aParent));
98
99 ComAssertRet(aParent, E_INVALIDARG);
100
101 /* Enclose the state transition NotReady->InInit->Ready */
102 AutoInitSpan autoInitSpan(this);
103 AssertReturn(autoInitSpan.isOk(), E_FAIL);
104
105 unconst(mParent) = aParent;
106 /* mPeer is left null */
107
108 mData.allocate();
109
110 /* Confirm a successful initialization */
111 autoInitSpan.setSucceeded();
112
113 return S_OK;
114}
115
116/**
117 * Initializes the graphics adapter object given another graphics adapter
118 * object (a kind of copy constructor). This object shares data with
119 * the object passed as an argument.
120 *
121 * @note This object must be destroyed before the original object
122 * it shares data with is destroyed.
123 *
124 * @note Locks @a aThat object for reading.
125 */
126HRESULT GraphicsAdapter::init(Machine *aParent, GraphicsAdapter *aThat)
127{
128 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
129
130 ComAssertRet(aParent && aThat, E_INVALIDARG);
131
132 /* Enclose the state transition NotReady->InInit->Ready */
133 AutoInitSpan autoInitSpan(this);
134 AssertReturn(autoInitSpan.isOk(), E_FAIL);
135
136 unconst(mParent) = aParent;
137 unconst(mPeer) = aThat;
138
139 AutoCaller thatCaller(aThat);
140 AssertComRCReturnRC(thatCaller.hrc());
141
142 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
143 mData.share(aThat->mData);
144
145 /* Confirm a successful initialization */
146 autoInitSpan.setSucceeded();
147
148 return S_OK;
149}
150
151/**
152 * Initializes the graphics adapter object given another graphics adapter
153 * object (a kind of copy constructor). This object makes a private copy
154 * of data of the original object passed as an argument.
155 *
156 * @note Locks @a aThat object for reading.
157 */
158HRESULT GraphicsAdapter::initCopy(Machine *aParent, GraphicsAdapter *aThat)
159{
160 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
161
162 ComAssertRet(aParent && aThat, E_INVALIDARG);
163
164 /* Enclose the state transition NotReady->InInit->Ready */
165 AutoInitSpan autoInitSpan(this);
166 AssertReturn(autoInitSpan.isOk(), E_FAIL);
167
168 unconst(mParent) = aParent;
169 /* mPeer is left null */
170
171 AutoCaller thatCaller(aThat);
172 AssertComRCReturnRC(thatCaller.hrc());
173
174 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
175 mData.attachCopy(aThat->mData);
176
177 /* Confirm a successful initialization */
178 autoInitSpan.setSucceeded();
179
180 return S_OK;
181}
182
183/**
184 * Uninitializes the instance and sets the ready flag to FALSE.
185 * Called either from FinalRelease() or by the parent when it gets destroyed.
186 */
187void GraphicsAdapter::uninit()
188{
189 LogFlowThisFunc(("\n"));
190
191 /* Enclose the state transition Ready->InUninit->NotReady */
192 AutoUninitSpan autoUninitSpan(this);
193 if (autoUninitSpan.uninitDone())
194 return;
195
196 mData.free();
197
198 unconst(mPeer) = NULL;
199 unconst(mParent) = NULL;
200}
201
202// Wrapped IGraphicsAdapter properties
203/////////////////////////////////////////////////////////////////////////////
204
205HRESULT GraphicsAdapter::getGraphicsControllerType(GraphicsControllerType_T *aGraphicsControllerType)
206{
207 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
208
209 *aGraphicsControllerType = mData->graphicsControllerType;
210
211 return S_OK;
212}
213
214HRESULT GraphicsAdapter::setGraphicsControllerType(GraphicsControllerType_T aGraphicsControllerType)
215{
216 switch (aGraphicsControllerType)
217 {
218 case GraphicsControllerType_Null:
219 case GraphicsControllerType_VBoxVGA:
220#ifdef VBOX_WITH_VMSVGA
221 case GraphicsControllerType_VMSVGA:
222 case GraphicsControllerType_VBoxSVGA:
223#endif
224 case GraphicsControllerType_QemuRamFB:
225 break;
226 default:
227 return setError(E_INVALIDARG, tr("The graphics controller type (%d) is invalid"), aGraphicsControllerType);
228 }
229
230 /* the machine needs to be mutable */
231 AutoMutableStateDependency adep(mParent);
232 if (FAILED(adep.hrc())) return adep.hrc();
233
234 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
235
236 mParent->i_setModified(Machine::IsModified_GraphicsAdapter);
237 mData.backup();
238 mData->graphicsControllerType = aGraphicsControllerType;
239
240 return S_OK;
241}
242
243HRESULT GraphicsAdapter::getVRAMSize(ULONG *aVRAMSize)
244{
245 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
246
247 *aVRAMSize = mData->ulVRAMSizeMB;
248
249 return S_OK;
250}
251
252HRESULT GraphicsAdapter::setVRAMSize(ULONG aVRAMSize)
253{
254 /* the machine needs to be mutable */
255 AutoMutableStateDependency adep(mParent);
256 if (FAILED(adep.hrc())) return adep.hrc();
257
258 ULONG uMin, uMax;
259 HRESULT hrc = PlatformProperties::s_getSupportedVRAMRange(mData->graphicsControllerType, mData->fAccelerate3D,
260 &uMin, &uMax, NULL /* aStrideSizeMB */);
261 if (FAILED(hrc))
262 return setError(hrc,
263 tr("Error getting VRAM range for selected graphics controller"));
264
265 /* check VRAM limits */
266 if ( aVRAMSize < uMin
267 || aVRAMSize > uMax)
268 return setError(E_INVALIDARG,
269 tr("Invalid VRAM size: %lu MB (must be in range [%lu, %lu] MB)"),
270 aVRAMSize, uMin, uMax);
271
272 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
273
274 mParent->i_setModified(Machine::IsModified_GraphicsAdapter);
275 mData.backup();
276 mData->ulVRAMSizeMB = aVRAMSize;
277
278 return S_OK;
279}
280
281/**
282 * Static helper function to return all supported features for a given graphics controller.
283 *
284 * @returns VBox status code.
285 * @param enmController Graphics controller to return supported features for.
286 * @param vecSupportedGraphicsControllerFeatures Returned features on success.
287 */
288/* static */
289int GraphicsAdapter::s_getSupportedFeatures(GraphicsControllerType_T enmController,
290 std::vector<GraphicsFeature_T> &vecSupportedGraphicsFeatures)
291{
292 switch (enmController)
293 {
294#ifdef VBOX_WITH_VMSVGA
295 case GraphicsControllerType_VBoxSVGA:
296 {
297 static const GraphicsFeature_T s_aGraphicsFeatures[] =
298 {
299# ifdef VBOX_WITH_VIDEOHWACCEL
300 GraphicsFeature_Acceleration2DVideo,
301# endif
302# ifdef VBOX_WITH_3D_ACCELERATION
303 GraphicsFeature_Acceleration3D
304# endif
305 };
306 MY_VECTOR_ASSIGN_ARRAY(vecSupportedGraphicsFeatures, s_aGraphicsFeatures);
307 break;
308 }
309#endif
310 case GraphicsControllerType_VBoxVGA:
311 RT_FALL_THROUGH();
312 case GraphicsControllerType_QemuRamFB:
313 {
314 static const GraphicsFeature_T s_aGraphicsFeatures[] =
315 {
316 GraphicsFeature_None
317 };
318 MY_VECTOR_ASSIGN_ARRAY(vecSupportedGraphicsFeatures, s_aGraphicsFeatures);
319 break;
320 }
321
322 default:
323 return VERR_INVALID_PARAMETER;
324 }
325
326 return VINF_SUCCESS;
327}
328
329/**
330 * Static helper function to return whether a given graphics feature for a graphics controller is enabled or not.
331 *
332 * @returns \c true if the given feature is supported, or \c false if not.
333 * @param enmController Graphics controlller to query a feature for.
334 * @param enmFeature Feature to query.
335 */
336/* static */
337bool GraphicsAdapter::s_isFeatureSupported(GraphicsControllerType_T enmController, GraphicsFeature_T enmFeature)
338{
339 std::vector<GraphicsFeature_T> vecSupportedGraphicsFeatures;
340 int vrc = GraphicsAdapter::s_getSupportedFeatures(enmController, vecSupportedGraphicsFeatures);
341 if (RT_SUCCESS(vrc))
342 return std::find(vecSupportedGraphicsFeatures.begin(),
343 vecSupportedGraphicsFeatures.end(), enmFeature) != vecSupportedGraphicsFeatures.end();
344 return false;
345}
346
347HRESULT GraphicsAdapter::setFeature(GraphicsFeature_T aFeature, BOOL aEnabled)
348{
349 /* the machine needs to be mutable */
350 AutoMutableStateDependency adep(mParent);
351 if (FAILED(adep.hrc())) return adep.hrc();
352
353 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
354
355 /* Validate if the given feature is supported by this graphics controller. */
356 if (!GraphicsAdapter::s_isFeatureSupported(mData->graphicsControllerType, aFeature))
357 return setError(VBOX_E_NOT_SUPPORTED, tr("The graphics controller does not support the given feature"));
358
359 bool *pfSetting = NULL;
360 switch (aFeature)
361 {
362 case GraphicsFeature_Acceleration2DVideo:
363 pfSetting = &mData->fAccelerate2DVideo;
364 break;
365
366 case GraphicsFeature_Acceleration3D:
367 pfSetting = &mData->fAccelerate3D;
368 break;
369
370 default:
371 break;
372 }
373
374 if (!pfSetting)
375 return setError(E_NOTIMPL, tr("The given feature is not implemented"));
376
377 if (*pfSetting != RT_BOOL(aEnabled))
378 {
379 mParent->i_setModified(Machine::IsModified_GraphicsAdapter);
380 mData.backup();
381
382 *pfSetting = RT_BOOL(aEnabled);
383 }
384
385 return S_OK;
386}
387
388HRESULT GraphicsAdapter::isFeatureEnabled(GraphicsFeature_T aFeature, BOOL *aEnabled)
389{
390 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
391
392 bool *pfSetting = NULL;
393
394 switch (aFeature)
395 {
396#ifndef VBOX_WITH_VIRT_ARMV8 /* On macOS (ARM) we don't support any 2D/3D acceleration for now. */
397 case GraphicsFeature_Acceleration2DVideo:
398 pfSetting = &mData->fAccelerate2DVideo;
399 *pfSetting = false; /* @bugref{9691} -- The legacy VHWA acceleration has been disabled completely. */
400 break;
401
402 case GraphicsFeature_Acceleration3D:
403 pfSetting = &mData->fAccelerate3D;
404 break;
405#endif
406 default:
407 break;
408 }
409
410 if (!pfSetting)
411 return VBOX_E_NOT_SUPPORTED;
412
413 *aEnabled = *pfSetting;
414
415 return S_OK;
416}
417
418HRESULT GraphicsAdapter::getMonitorCount(ULONG *aMonitorCount)
419{
420 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
421
422 *aMonitorCount = mData->cMonitors;
423
424 return S_OK;
425}
426
427HRESULT GraphicsAdapter::setMonitorCount(ULONG aMonitorCount)
428{
429 /* make sure monitor count is a sensible number */
430 if (aMonitorCount < 1 || aMonitorCount > SchemaDefs::MaxGuestMonitors)
431 return setError(E_INVALIDARG,
432 tr("Invalid monitor count: %lu (must be in range [%lu, %lu])"),
433 aMonitorCount, 1, SchemaDefs::MaxGuestMonitors);
434
435 /* the machine needs to be mutable */
436 AutoMutableStateDependency adep(mParent);
437 if (FAILED(adep.hrc())) return adep.hrc();
438
439 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
440
441 mParent->i_setModified(Machine::IsModified_GraphicsAdapter);
442 mData.backup();
443 mData->cMonitors = aMonitorCount;
444
445 return S_OK;
446}
447
448// Wrapped IGraphicsAdapter methods
449/////////////////////////////////////////////////////////////////////////////
450
451// public methods only for internal purposes
452/////////////////////////////////////////////////////////////////////////////
453
454/**
455 * Loads settings from the given machine node.
456 * May be called once right after this object creation.
457 *
458 * @param data Configuration settings.
459 *
460 * @note Locks this object for writing.
461 */
462HRESULT GraphicsAdapter::i_loadSettings(const settings::GraphicsAdapter &data)
463{
464 AutoCaller autoCaller(this);
465 AssertComRCReturnRC(autoCaller.hrc());
466
467 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
468
469 mData.assignCopy(&data);
470
471 return S_OK;
472}
473
474/**
475 * Saves settings to the given machine node.
476 *
477 * @param data Configuration settings.
478 *
479 * @note Locks this object for reading.
480 */
481HRESULT GraphicsAdapter::i_saveSettings(settings::GraphicsAdapter &data)
482{
483 AutoCaller autoCaller(this);
484 AssertComRCReturnRC(autoCaller.hrc());
485
486 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
487
488 data = *mData.data();
489
490 return S_OK;
491}
492
493/**
494 * @note Locks this object for writing.
495 */
496void GraphicsAdapter::i_rollback()
497{
498 /* sanity */
499 AutoCaller autoCaller(this);
500 AssertComRCReturnVoid(autoCaller.hrc());
501
502 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
503
504 mData.rollback();
505}
506
507/**
508 * @note Locks this object for writing, together with the peer object (also
509 * for writing) if there is one.
510 */
511void GraphicsAdapter::i_commit()
512{
513 /* sanity */
514 AutoCaller autoCaller(this);
515 AssertComRCReturnVoid(autoCaller.hrc());
516
517 /* sanity too */
518 AutoCaller peerCaller(mPeer);
519 AssertComRCReturnVoid(peerCaller.hrc());
520
521 /* lock both for writing since we modify both (mPeer is "master" so locked
522 * first) */
523 AutoMultiWriteLock2 alock(mPeer, this COMMA_LOCKVAL_SRC_POS);
524
525 if (mData.isBackedUp())
526 {
527 mData.commit();
528 if (mPeer)
529 {
530 /* attach new data to the peer and reshare it */
531 mPeer->mData.attach(mData);
532 }
533 }
534}
535
536/**
537 * @note Locks this object for writing, together with the peer object
538 * represented by @a aThat (locked for reading).
539 */
540void GraphicsAdapter::i_copyFrom(GraphicsAdapter *aThat)
541{
542 AssertReturnVoid(aThat != NULL);
543
544 /* sanity */
545 AutoCaller autoCaller(this);
546 AssertComRCReturnVoid(autoCaller.hrc());
547
548 /* sanity too */
549 AutoCaller thatCaller(aThat);
550 AssertComRCReturnVoid(thatCaller.hrc());
551
552 /* peer is not modified, lock it for reading (aThat is "master" so locked
553 * first) */
554 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
555 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
556
557 /* this will back up current data */
558 mData.assignCopy(aThat->mData);
559}
560/* vi: set tabstop=4 shiftwidth=4 expandtab: */
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