Graphics card profiles: Difference between revisions

From FlightGear wiki
Jump to navigation Jump to search
Line 45: Line 45:


We can do that by setting /sim/rendering/* as required, i.e. loading pre-configured profiles from $FG_ROOT.  
We can do that by setting /sim/rendering/* as required, i.e. loading pre-configured profiles from $FG_ROOT.  
For example, $FG_ROOT/gui/dialogs/about.xml and rendering.xml are already accessing some of the GL* data via properties, e.g. to display the Intel warning, but also the GPU vendor info:
For example, $FG_ROOT {{Fgdata file|gui/dialogs/about.xml}} and {{Fgdata file|gui/dialogs/rendering.xml}} are already accessing some of the GL* data via properties, e.g. to display the Intel warning, but also the GPU vendor info:


[[File:About dialog 2.10.png|250px|[[About dialog]] ]]
[[File:About dialog 2.10.png|250px|[[About dialog]] ]]

Revision as of 09:53, 25 February 2016

This article is a stub. You can help the wiki by expanding it.
This article describes content/features that may not yet be available in the latest stable version of FlightGear (2020.3).
You may need to install some extra components, use the latest development (Git) version or even rebuild FlightGear from source, possibly from a custom topic branch using special build settings: .

This feature is scheduled for FlightGear (unknown). 10}% completed

If you'd like to learn more about getting your own ideas into FlightGear, check out Implementing new features for FlightGear.

Motivation

This particular idea dates back to early 2016 when a few FlightGear contributors were discussing a reddit review of FlightGear on the forum which highlighted that FlightGear's default graphics settings didn't seem to fit/match the graphics hardware available, i.e. rather plain default settings compared to the powerful graphics card available.

Background

FlightGear core deveoper Erik Hofman came up with the idea to preselect more appropriate default settings based on parsing various GL_* strings (in particular GL_VENDOR), i.e. detect the video card and based on the GL renderer name turn on ALS (or not), turn on water shader (or not), turn on the 3d city shader (or not), etc.

Idea

This approach is largely inspired by the way FlightGear already supports a variety of different joysticks and other I/O hardware using XML-configurable hardware profiles.

The defaults would not be touched but based on the detected video card certain options would get enabled, making the first impression much more pleasant (for first time users). [1]

Furthermore, people agreed that it could be a good idea to make sure the configuration has at least 30fps at the default airport.

Also it would be a one time configuration for after a (re)install. The settings would be written to a local configuration afterwards so users could still tweak for their own liking.[2]

Other contributors, like Thorsten mentioned, that it does not seem to be a technical problem - to query a string from the property tree is easy, to write a routine which sets other properties based on what the string says is equally easy.

The problem is the meat of it - someone has to know what settings are likely to run on what graphics cards. And someone has to write the routine that does it. Then it's done. [3]

We can do that by setting /sim/rendering/* as required, i.e. loading pre-configured profiles from $FG_ROOT. For example, $FG_ROOT fgdata/gui/dialogs/about.xml and fgdata/gui/dialogs/rendering.xml are already accessing some of the GL* data via properties, e.g. to display the Intel warning, but also the GPU vendor info:

About dialog

Thus, we would ideally introduce 3-4 "vendor"-specific folders and then introduce a PropertyList XML file where the RENDERER string is used to select a certain default configuration. For testing purposes, we could promote this features on the forum/website/IRC and facebook to get people involved with testing, and to provide feedback - so that we know what settings work well enough, using Nasal's http APIs, such feedback could even be gathered online. [4]

However, CPU/RAM and VRAM info is not currently available, but we have patches providing this sort of info [5] :

Resource Tracking for FlightGear


  1. erik (Feb 7th, 2016). Re: Review of FG on reddit: xpost.
  2. erik (Feb 8th, 2016). Re: Review of FG on reddit: xpost.
  3. Thorsten (Feb 7th, 2016). Re: Review of FG on reddit: xpost.
  4. Hooray (Feb 8th, 2016). Re: Review of FG on reddit: xpost.
  5. Hooray (Feb 7th, 2016). Re: Review of FG on reddit: xpost.

Approach

It's basically a form of feature-scaling: Feature Scaling

We could expose most of the GL* info at the property tree level, and then use Nasal/propertylist rules (and/or SGConditions) to dynamically toggle features on/off during startup, i.e. sort of a better customiable initialization sequence.

The easiest way to implement something like this would be supporting "data overlays", i.e. in the form of fgfsrc/preferences.xml files that are stored in $FG_ROOT/Profiles and automatically overlaid over default startup options once a certain GL vendor/make and GPU model are detected, e.g. by having:

  • $FG_ROOT/GraphicsProfiles/NVIDIA
  • $FG_ROOT/GraphicsProfiles/AMD-ATI
  • $FG_ROOT/GraphicsProfiles/INTEL
  • $FG_ROOT/Graphics Profiles/MATROX
  • $FG_ROOT/GraphicsProfiles/Other

Each vendor-specific sub-folder could then contain graphics related xml overlays that will be loaded on top of the default startup options (i.e. those not customized/overriden by the user) - what that means is that the current hard-coded default settings in fg_init.cxx would need to be dynamically loaded during startup using the APIs from props_io.cxx.

The corresponding startup profiles could be either conventional PropertyList XML files, or support embedded Nasal/property-rule blocks to provide support for regex-matching etc.[1]

This is something where it would make sense to provide a benchmark and test various combination of settings on different systems and gather all results in a central database to determine a safe subset of settings that should work for most AMD/ATI, NVIDIA and Intel boards - note that the CrashRpt tool is already gathering feedback on crashes and sending that to a webserver, where it is stored in a database. [2]

We could provide a --disable-gpu-profiles parameter to resort to the old/standard behavior, or require people to explicitly enable the new system via something like --enable-gpu-profiles, i.e. trying to pick an appropriate set of standard settings.

The more difficult thing is fixing up subsystems that are not currently able to be reset/restarted with restarting FG as a whole Note that the rendering settings dialog will already detect the INTEL substring and show a warning if appropriate [3]


  1. Hooray (Feb 7th, 2016). Re: Review of FG on reddit: xpost.
  2. Hooray (Feb 7th, 2016). Re: Review of FG on reddit: xpost.
  3. Hooray (Feb 7th, 2016). Re: Review of FG on reddit: xpost.

Status

Issues

When preferences.xml, autosave.xml etc are loaded, the gl-vendor properties are not yet initialized, because that requires an actual GC (OSG graphics context), so that loading the overlay may need to be delayed or the initialization sequence changed accordingly.

We could also store a copy of the rendering specific state from autosave.xml and apply that within the GC::run() method, i.e. after loading graphics profiles there (straightforward).

Alternatively, it would be possible to delegate the control flow to Nasal space to handle loading suitable defaults for the detected vendor/renderer.


flightgear/src/GUI/gui.cxx (line 102)

// Operation for querying OpenGL parameters. This must be done in a
// valid OpenGL context, potentially in another thread.

struct GeneralInitOperation : public GraphicsContextOperation
{
    GeneralInitOperation()
        : GraphicsContextOperation(std::string("General init"))
    {
    }
    void run(osg::GraphicsContext* gc)
    {
        SGPropertyNode* simRendering = fgGetNode("/sim/rendering");

        simRendering->setStringValue("gl-vendor", (char*) glGetString(GL_VENDOR));
        SG_LOG( SG_GENERAL, SG_INFO, glGetString(GL_VENDOR));

        simRendering->setStringValue("gl-renderer", (char*) glGetString(GL_RENDERER));
        SG_LOG( SG_GENERAL, SG_INFO, glGetString(GL_RENDERER));

        simRendering->setStringValue("gl-version", (char*) glGetString(GL_VERSION));
        SG_LOG( SG_GENERAL, SG_INFO, glGetString(GL_VERSION));

        // Old hardware without support for OpenGL 2.0 does not support GLSL and
        // glGetString returns NULL for GL_SHADING_LANGUAGE_VERSION.
        //
        // See http://flightgear.org/forums/viewtopic.php?f=17&t=19670&start=15#p181945
        const char* glsl_version = (const char*) glGetString(GL_SHADING_LANGUAGE_VERSION);
        if( !glsl_version )
          glsl_version = "UNSUPPORTED";
        simRendering->setStringValue("gl-shading-language-version", glsl_version);
        SG_LOG( SG_GENERAL, SG_INFO, glsl_version);

        GLint tmp;
        glGetIntegerv( GL_MAX_TEXTURE_SIZE, &tmp );
        simRendering->setIntValue("max-texture-size", tmp);

        glGetIntegerv( GL_DEPTH_BITS, &tmp );
        simRendering->setIntValue("depth-buffer-bits", tmp);
    }
};

Roadmap

Organization of Profiles

Implementation

This could work pretty much like the joystick support - i.e. we would maintain PropertyList XML files in $FG_ROOT/GraphicsProfiles/VENDOR, and then use the GL_* strings to load a matching default profile, with CLI arguments being processed afterwards, i.e. to take precedence, so that defaults can be overridden.

For instance, see $FG_SRCflightgear/Main/fg_init.cxx (line 466) fgInitConfig():

bool loadDefaults = options->shouldLoadDefaultConfig();
if (loadDefaults) {
// Read global preferences from $FG_ROOT/preferences.xml
SG_LOG(SG_INPUT, SG_INFO, "Reading global preferences");
fgLoadProps("preferences.xml", globals->get_props());
SG_LOG(SG_INPUT, SG_INFO, "Finished Reading global preferences");

This is one of the places, where we could also run another fgLoadPRops() call to load rendering settings that are overlaid onto /sim/rendering

Technically, we are already using this approach to suport translations, which are also read/overlaid into the tree[1]


  1. Hooray (Feb 8th, 2016). Re: Review of FG on reddit: xpost.

Proof of Concept

WIP.png Work in progress
This article or section will be worked on in the upcoming hours or days.
See history for the latest developments.


Note  This is just intended to demonstrate the concept; as mentioned before, it would make more sense to move this to the run() method of the GeneralInitOperation struct, so that we can access the gl-vendor and gl-renderer information to proceed from here. Doing that will require to restore a copy of any autosave.xml settings, i.e. those having the userarchive attribute set.

To actually do some kind of heuristics processing, it would make sense to support SGConditions, PropertyRules and/or Nasal (at least temporarily), so that we can process a few properties and select appropriate defaults.

diff --git a/src/Main/fg_init.cxx b/src/Main/fg_init.cxx
index b7fea20..615d0a9 100644
--- a/src/Main/fg_init.cxx
+++ b/src/Main/fg_init.cxx
@@ -469,7 +469,24 @@ int fgInitConfig ( int argc, char **argv, bool reinit )
       SG_LOG(SG_INPUT, SG_INFO, "Reading global preferences");
       fgLoadProps("preferences.xml", globals->get_props());
       SG_LOG(SG_INPUT, SG_INFO, "Finished Reading global preferences");
-        
+    
+      // Next, try to load defaults for /sim/rendering
+      SGPropertyNode* fgroot = globals->get_props();
+      try {
+      	SGPropertyNode* rendering = fgroot->getNode("/sim/rendering");
+	std::string path = "Profiles/graphics.xml"; 
+	if(rendering) {
+		SG_LOG(SG_INPUT, SG_INFO, "Loading graphics profiles from:" <<path);
+      		fgLoadProps(path.c_str(), rendering);
+		}
+	else SG_LOG(SG_INPUT, SG_ALERT, "Could not acquire handle to /sim/rendering for loading graphics profile from "<<path);
+      }
+      catch (const std::exception& e) {
+                SG_LOG(SG_INPUT, SG_INFO, "caught std::exception trying to read graphics profile");
+            } catch (...) {
+                SG_LOG(SG_INPUT, SG_INFO, "caught generic exception trying to read graphics profile");
+            }
+
       // do not load user settings when reset to default is requested, or if
       // told to explicitly ignore
       if (options->isOptionSet("restore-defaults") || options->isOptionSet("ignore-autosave"))
Note  This is to be put into $FG_ROOT/Profiles/graphics.xml (for now, this is just a copy of the /sim/rendering portion of preferences.xml )
<?xml version="1.0"?>
<!--
************************************************************************
Graphics defaults for FlightGear property values.

Started February 2016: 
************************************************************************
-->
<PropertyList>
  <sim>
    <rendering>
      <materials-file>Materials/regions/materials.xml</materials-file>
      <rembrandt>
        <enabled type="bool">false</enabled>
        <renderer>default-pipeline</renderer>
        <show-buffers type="bool" userarchive="y">false</show-buffers>
        <ambient-occlusion type="bool" userarchive="y">false</ambient-occlusion>
        <ambient-occlusion-strength type="float" userarchive="y">0.6</ambient-occlusion-strength>
        <ambient-occlusion-buffers type="bool">true</ambient-occlusion-buffers>
        <bloom type="bool" userarchive="y">true</bloom>
        <bloom-strength type="float" userarchive="y">0.6</bloom-strength>
        <bloom-buffers type="bool">true</bloom-buffers>
        <night-vision type="bool">false</night-vision>
        <cinema>
          <vignette type="bool">false</vignette>
          <inner-circle type="float" userarchive="y">0.8</inner-circle>
          <outer-circle type="float" userarchive="y">1.3</outer-circle>
          <color-shift type="bool">false</color-shift>
          <red-shift>
            <x type="float" userarchive="y">.393</x>
            <y type="float" userarchive="y">.769</y>
            <z type="float" userarchive="y">.189</z>
          </red-shift>
          <green-shift>
            <x type="float" userarchive="y">.349</x>
            <y type="float" userarchive="y">.686</y>
            <z type="float" userarchive="y">.168</z>
          </green-shift>
          <blue-shift>
            <x type="float" userarchive="y">.272</x>
            <y type="float" userarchive="y">.534</y>
            <z type="float" userarchive="y">.131</z>
          </blue-shift>
          <distortion type="bool">false</distortion>
          <distortion-factor>
            <x type="float" userarchive="y">0.0</x>
            <y type="float" userarchive="y">0.0</y>
            <z type="float" userarchive="y">1.0</z>
          </distortion-factor>
          <color-fringe type="bool">false</color-fringe>
          <color-fringe-factor type="float" userarchive="y">1.0</color-fringe-factor>
          <film-wear type="bool">false</film-wear>
        </cinema>
        <exposure type="float" userarchive="y">1.0</exposure>
        <use-color-for-depth type="bool">false</use-color-for-depth>
        <no-16bit-buffer type="bool">false</no-16bit-buffer>
        <debug-buffer n="0">
          <enabled type="bool" userarchive="y">false</enabled>
          <name userarchive="y"/>
        </debug-buffer>
        <debug-buffer n="1">
          <enabled type="bool" userarchive="y">true</enabled>
          <name userarchive="y">spec-emis</name>
        </debug-buffer>
        <debug-buffer n="2">
          <enabled type="bool" userarchive="y">true</enabled>
          <name userarchive="y">normal</name>
        </debug-buffer>
        <debug-buffer n="3">
          <enabled type="bool" userarchive="y">true</enabled>
          <name userarchive="y">diffuse</name>
        </debug-buffer>
        <debug>
          <lighting>
            <sky type="bool">true</sky>
            <ambient type="bool">true</ambient>
            <sunlight type="bool">true</sunlight>
            <lights type="bool">true</lights>
            <fog type="bool">true</fog>
            <debug type="bool">false</debug>
            <transparent type="bool">false</transparent>
          </lighting>
        </debug>
      </rembrandt>
      <debug type="bool">false</debug>
      <realism type="int">5</realism>
      <filtering type="int">8</filtering>
      <shaders>
        <custom-settings type="bool" userarchive="y">false</custom-settings>
        <generic type="float" userarchive="y">1.0</generic>
        <landmass type="float" userarchive="y">1.0</landmass>
        <model type="float" userarchive="y">1.0</model>
        <contrails type="float" userarchive="y">1.0</contrails>
        <crop type="float" userarchive="y">1.0</crop>
        <skydome type="bool" userarchive="y">false</skydome>
        <transition type="float" userarchive="y">1.0</transition>
        <urban type="float" userarchive="y">1.0</urban>
        <water type="float" userarchive="y">1.0</water>
        <wind-effects type="float" userarchive="y">0.0</wind-effects>
        <forest type="float" userarchive="y">0.0</forest>
        <lights type="float" userarchive="y">1.0</lights>
        <quality-level-internal type="float" userarchive="y">1.0</quality-level-internal>
      </shaders>
      <mie type="float" userarchive="y">0.003</mie>
      <rayleigh type="float" userarchive="y">0.0003</rayleigh>
      <dome-density type="float" userarchive="y">0.5</dome-density>
      <!--
			<multithreading-mode>AutomaticSelection</multithreading-mode>
     Uncomment the above element to select OSG multi-threading mode.
     This may improve performance on multi-core, multi-CPU
     and/or multi-GPU systems. The recommended setting is AutomaticSelection.
     The alternatives are
       AutomaticSelection
       DrawThreadPerContext
       CullDrawThreadPerContext
       CullThreadPerCameraDrawThreadPerContext
   -->
      <plod-minimum-expiry-time-secs type="double" userarchive="y">180.0</plod-minimum-expiry-time-secs>
      <static-lod>
        <detailed type="double" userarchive="y">1500</detailed>
        <rough type="double" userarchive="y">9000</rough>
        <bare type="double" userarchive="y">30000</bare>
        <!--
          ai-range-mode-pixel: true=use pixel size on screen, false=use distance from eyepoint 
          With /sim/rendering/static-lod/ai-range-mode-pixel set to true
          /sim/rendering/static-lod/ai-detailed now contains the minimum size of the
          model on the screen to be displayed. Values of 10-50 seem to make some sense.
        -->
        <ai-range-mode-pixel type="bool" userarchive="y">false</ai-range-mode-pixel>
        <ai-detailed type="double" userarchive="y">10000</ai-detailed>
        <!-- ai-bare type="double" userarchive="y">10000</ai-bare -->
        <ai-interior type="double" userarchive="y">50</ai-interior>
      </static-lod>
      <random-objects type="bool" userarchive="y">true</random-objects>
      <random-vegetation type="bool" userarchive="y">true</random-vegetation>
      <random-vegetation-shadows type="bool" userarchive="y">false</random-vegetation-shadows>
      <random-vegetation-normals type="bool" userarchive="y">false</random-vegetation-normals>
      <vegetation-density type="double" userarchive="y">1.0</vegetation-density>
      <random-buildings type="bool" userarchive="y">false</random-buildings>
      <building-density type="double" userarchive="y">1.0</building-density>
      <horizon-effect type="bool" userarchive="y">false</horizon-effect>
      <point-sprites type="bool" userarchive="y">true</point-sprites>
      <enhanced-lighting type="bool" userarchive="y">false</enhanced-lighting>
      <distance-attenuation type="bool" userarchive="y">false</distance-attenuation>
      <particles type="bool" userarchive="y">true</particles>
      <precipitation-gui-enable type="bool" userarchive="y">false</precipitation-gui-enable>
      <precipitation-enable type="bool" userarchive="y">false</precipitation-enable>
      <precipitation-aircraft-enable type="bool">true</precipitation-aircraft-enable>
      <precipitation>
        <!-- streaks coloring and transparency -->
        <min-light type="float">0.35</min-light>
        <streak-brightness-nearmost-layer type="float">0.9</streak-brightness-nearmost-layer>
        <streak-brightness-farmost-layer type="float">0.5</streak-brightness-farmost-layer>
        <!-- streak period as a function of the speed, decreases with speed -->
        <streak-period-max type="float">2.5</streak-period-max>
        <streak-period-change-per-kt type="float">0.005</streak-period-change-per-kt>
        <streak-period-min type="float">1.0</streak-period-min>
        <!-- streak length as a function of the speed, increases with speed -->
        <streak-length-min type="float">0.03</streak-length-min>
        <streak-length-change-per-kt type="float">0.0005</streak-length-change-per-kt>
        <streak-length-max type="float">0.1</streak-length-max>
        <!-- # of rain streaks at the 100.0% precipitation density -->
        <streak-count-min type="int">40</streak-count-min>
        <!-- lightest rain -->
        <streak-count-max type="int">190</streak-count-max>
        <!-- heaviest rain -->
        <!-- numbers over MAX_RAIN_SLICE in simgear/environment/visual_enviro.cxx
         will be ignored in the current implementation.  -->
        <!-- the precipitation cone geometry -->
        <cone-base-radius type="float">15.0</cone-base-radius>
        <cone-height type="float">30.0</cone-height>
      </precipitation>
      <lightning-enable type="bool" userarchive="y">false</lightning-enable>
      <specular-highlight type="bool" userarchive="y">false</specular-highlight>
      <bump-mapping type="bool" userarchive="y">false</bump-mapping>
      <clouds3d-enable type="bool" userarchive="y">false</clouds3d-enable>
      <clouds3d-vis-range type="float" userarchive="y">10000.0</clouds3d-vis-range>
      <clouds3d-detail-range type="float" userarchive="y">10000.0</clouds3d-detail-range>
      <clouds3d-density type="float" userarchive="y">0.25</clouds3d-density>
      <!-- legacy property to control drawing 'out the window', i.e
            non-cockpit + aircraft elements. Use draw-mask instead. -->
      <draw-otw type="bool">true</draw-otw>
      <draw-mask>
        <terrain type="bool">true</terrain>
        <models type="bool">true</models>
        <aircraft type="bool">true</aircraft>
        <clouds type="bool">true</clouds>
      </draw-mask>
      <shadows-ac type="bool" userarchive="y">false</shadows-ac>
      <shadows-ac-transp type="bool" userarchive="y">false</shadows-ac-transp>
      <shadows-ai type="bool" userarchive="y">false</shadows-ai>
      <shadows-to type="bool" userarchive="y">false</shadows-to>
      <shadows-debug type="bool" userarchive="y">false</shadows-debug>
      <shadows>
        <enabled type="bool" userarchive="y">true</enabled>
        <debug type="bool" userarchive="y">false</debug>
        <map-size type="int" userarchive="y">2048</map-size>
        <num-cascades type="int" userarchive="y">4</num-cascades>
        <cascade-far-m n="0" type="float" userarchive="y">2.0</cascade-far-m>
        <cascade-far-m n="1" type="float" userarchive="y">8.0</cascade-far-m>
        <cascade-far-m n="2" type="float" userarchive="y">32.0</cascade-far-m>
        <cascade-far-m n="3" type="float" userarchive="y">128.0</cascade-far-m>
        <filtering type="int" userarchive="y">1</filtering>
      </shadows>
      <shader-experimental type="bool" userarchive="y">false</shader-experimental>
      <shader-effects type="bool" userarchive="y">true</shader-effects>
      <fps-display type="bool" userarchive="y">false</fps-display>
      <frame-latency-display type="bool" userarchive="y">false</frame-latency-display>
      <on-screen-statistics type="int">0</on-screen-statistics>
      <glide-slope-tunnel type="bool" userarchive="y">false</glide-slope-tunnel>
      <redout>
        <enabled type="bool" userarchive="y">true</enabled>
        <parameters>
          <blackout-onset-g type="double">3.5</blackout-onset-g>
          <blackout-complete-g type="double">5</blackout-complete-g>
          <redout-onset-g type="double">-2</redout-onset-g>
          <redout-complete-g type="double">-4</redout-complete-g>
        </parameters>
      </redout>
      <headshake>
        <enabled type="bool" userarchive="y">false</enabled>
        <rate-m-g type="double">0.005</rate-m-g>
      </headshake>
      <osg-displaysettings>
        <eye-separation type="double" userarchive="y">0.05</eye-separation>
        <screen-distance type="double" userarchive="y">0.5</screen-distance>
        <stereo-mode type="string" userarchive="y">OFF</stereo-mode>
      </osg-displaysettings>
      <osg-notify-level type="string" userarchive="y">warn</osg-notify-level>
      <cache type="bool">true</cache>
      <use-vbos type="bool">false</use-vbos>
      <terrain>
        <simplifier>
          <enabled-near type="bool">false</enabled-near>
          <enabled-far type="bool">false</enabled-far>
          <ratio type="double">0.01</ratio>
          <max-error type="double">3000.0</max-error>
          <max-length type="double">1000.0</max-length>
        </simplifier>
      </terrain>
      <!-- OSG default is 300, but this means we burn lots of memory on no-longer
             visible trees / random buildings -->
      <max-paged-lod type="int">200</max-paged-lod>
      <als-secondary-lights>
        <use-searchlight type="bool">false</use-searchlight>
        <use-landing-light type="bool">false</use-landing-light>
        <use-alt-landing-light type="bool">false</use-alt-landing-light>
        <landing-light1-offset-deg type="float">0.0</landing-light1-offset-deg>
        <landing-light2-offset-deg type="float">0.0</landing-light2-offset-deg>
        <landing-light3-offset-deg type="float">0.0</landing-light3-offset-deg>
	<use-flashlight type="int">0</use-flashlight>
      </als-secondary-lights>
    </rendering>
</sim>      
</PropertyList>
<!-- end of graphics.xml -->