Hello,

attached is an updated dri configuration design. Most of the changes are
based on the feedback on the list and some things that became clearer
after reading the XML 1.0 recommendation. There are still enough of open
issues, so don't hesitate to comment on these. The most important one
that should be decided before the implementation starts is 3.3 (about
character encodings and gcc).

Best regards,
  Felix

------------    __\|/__    ___     ___       -------------------------
 Felix       ___\_e -_/___/ __\___/ __\_____   You can do anything,
   Kühling  (_____\Ä/____/ /_____/ /________)  just not everything
 [EMAIL PROTECTED]       \___/   \___/   U        at the same time.
DRI Configuration Infrastructure (Draft)
Revision 1

Felix Kühling <[EMAIL PROTECTED]>, D. Hageman <[EMAIL PROTECTED]>

05 March 2003


1. Introduction
---------------

Many proprietary OpenGL implementations come with configuration tools
which allow the customization of a large number of parameters. DRI
lacks such a configuration so far. The only way to modify the behavior
of the driver is through environment variables. The growing number of
environment variables and the demand for more configuration options
called for a consistent, flexible, robust and last but not least
user-friendly configuration infrastructure for DRI.

In an ongoing discussion in the last months a number of systems were
discussed. I'll summarize them here shortly (without any intention of
starting another discussion about the same topic ;-).

1. Keep the old system with environment variables. If you want to save
   the configuration for your favorite game write a wrapper script
   which sets the necessary environment variables and then runs the
   program.

2. Make an OpenGL wrapper library which is loaded via LD_PRELOAD and
   modifies the behavior of OpenGL transparently to the
   application. Thus no changes to the drivers are required.

3. The drivers read configuration options from a configuration file.

The discussion converged to the third option. A number of demands were
brought up which are listed here in no particular order.

 - It should be possible to change the configuration with a text editor.

 - It should be easy to implement GUI tools to edit the configuration.

 - The drivers themselves provide information about available
   configuration options to external programs.

 - Internationalized descriptions of driver options

 - Support for multi-headed setups

 - Configuration per application, per screen and/or driver

 - Keep indirect accelerated rendering in mind.

 - It should be possible for other driver vendors to adopt the same
   configuration scheme so that their drivers can be configured with
   the same configuration file and GUI.

2. Design
---------

This is a very early stage of a design. Often several options are
proposed with a personal preference or argument for one of them. The
frequent use of subjunctive will hopefully soon change to more
definite statements.

2.1 Configuration file format

For the configuration file and for advertising available options we
came to a general agreement (or at least the lack of disagreement) to
use XML. Advantages are that it is already used in the XFree86 font
configuration and a version of expat is included in the XFree86
distribution. It allows the creation of a structured format which can
accommodate configuration on a per application, per screen and per
driver basis. Furthermore there are XML bindings for a number of
scripting languages which will ease the creation of GUI configuration
tools. As a disadvantage the bad readability was commonly stated.

The W3C XML 1.0 Recommendation specifies the syntax of a well formed
XML document. DTDs (document type definitions) are used to define
element types and their attributes. The DTD used for the configuration
file is shown in an example of a configuration file:

<dri>
        <device>
                <!-- device independent configuration without a screen
                     or driver attribute -->
                <application name="Default">
                        <!-- Default application configuration has no
                             executable attribute. The name can be
                             chosen arbitrarily -->
                </application>
        </device>

        <device screen="0">
                <!-- device specification in terms of a X screen number -->
                <application name="Wolfenstein 3D (Multiplayer)" executable="wolfmp"> 
                        <!-- Name attribute is a nice human readable
                             name of an application.  The executable
                             attribute is most likely what a driver
                             would have to key off to determine a
                             configuration -->
                        <option name="debug_dma" value="true"/>
                        <option name="preferred_bpt" value="16"/>
                </application>
        </device>

        <device driver="radeon">
                <!-- device specification in terms of the DRI driver -->
        </device>
</dri>

2.2 Advertising available options

All information about available configuration options, including their
data type, valid range and verbal descriptions will be advertised by
the drivers. No knowledge about the drivers is required in an external
configuration GUI. This way the GUI always presents an up-to-date view
of all available options of the drivers currently
installed. Furthermore it would be possible for third party
binary-only drivers, which adopt this configuration scheme, to be
configured by the same GUI without modifications.

Available options will be described by an XML document which is
contained in a constant character array in the driver. An option
is defined by four attributes:

- option name
- data type (int, float, bool, ...)
- range or set of valid values (if applicable)
- default value

Furthermore internationalized verbal descriptions are associated with
each option.

Options will be grouped according to their purpose. This extra
information is not necessary for parsing or validating the
configuration file but it enables the GUI to present options in
comprehensible chunks.

An example shows how this can be expressed in XML:

<section>
        <description lang="en" text="Debugging"/>
        <description lang="de" text="Fehlersuche"/>

        <option name="debug_dma" type="bool" default="false">
                <description lang="en" text="Debug DMA buffers"/>
                <description lang="de" text="DMA Puffer debuggen"/>
        </option>
</section>

<section>
        <description lang="en" text="Texture"/>
        <description lang="de" text="Textur"/>

        <option name="preferred_bpt" type="int" valid="0,16,32" default="0">
                <description lang="en" text="Preferred texture color depth, 0 means 
'same as frame buffer'"/>
                <description lang="de" text="Bevorzugte Textur Farbtiefe, 0 bedeutet 
'so wie Framebuffer'"/>
        </option>

        <option name="stupid_example" type="float" valid="0.5-1.0,2.0-3.0" 
default="0.75">
        </option>
</section>

2.2.1 Proposed naming conventions

Options should be named in a consistent way. We propose to use only
lower case letters with words separated by underscores. Clearly
driver-specific options should start with a driver name prefix. Other
options don't have any prefix at all.

2.2.2 Pools of options

Many common options will be duplicated in several drivers, as for
instance the "preferred_bpt" example above. This makes maintaining the
description translations difficult and leads almost inevitably to
diverging translations of similar options in different
drivers. Therefore common options and their translations as well as
the section descriptions should be maintained in a central
place. However, it must still be possible to change the valid value
ranges and the default values in a driver-specific way.

A set of generic macros would help avoid quoting mistakes and make it
easier to change the format in early stages of development. Example:

#define DRI_OPT_BEGIN(name,type,def) \
"<option name=\""#name"\" type=\""#type"\" default=\""#def"\">\n"

#define DRI_OPT_BEGIN_V(name,type,valid,def) \
"<option name=\""#name"\" type=\""#type"\" valid=\""valid" default=\""#def"\">\n"

#define DRI_OPT_DESC(lang,text) \
"       <description lang=\""#lang"\" text=\""text"\"/>\n"

#define DRI_OPT_END \
"</option>\n"

#define DRI_OPT_SECTION_BEGIN \
"<section>\n"

#define DRI_OPT_SECTION_END \
"</section>\n"

Note that only the 'valid' and 'text' arguments have to be specified
as string literals and can contain punctuations which would otherwise
confuse the preprocessor. The option pool is a header file that uses
the generic macros in order to define one parametrized macro for each
option and one macro for each type of section:

#define DRI_OPT_SECTION_DEBUG \
DRI_OPT_SECTION_BEGIN \
        DRI_OPT_DESC(en,"Debugging") \
        DRI_OPT_DESC(de,"Fehlersuche")

#define DRI_OPT_SECTION_TEXTURE \
DRI_OPT_SECTION_BEGIN \
        DRI_OPT_DESC(en,"Texture") \
        DRI_OPT_DESC(de,"Textur")

#define DRI_OPT_DEBUG_DMA(def) \
DRI_OPT_BEGIN(debug_dma,bool,def) \
        DRI_OPT_DESC(en,"Debug DMA buffers") \
        DRI_OPT_DESC(de,"DMA Puffer debuggen") \
DRI_OPT_END

#define DRI_OPT_PREFERRED_BPT(valid,def) \
DRI_OPT_BEGIN_V(preferred_bpt,int,valid,def) \
        DRI_OPT_DESC(en,"Preferred texture color depth, 0 means 'same as frame 
buffer'") \
        DRI_OPT_DESC(de,"Bevorzugte Textur Farbtiefe, 0 bedeutet 'so wie 
Framebuffer'") \
DRI_OPT_END

Driver specific options will be maintained in the same way but in a
header file in the driver's own directory. Eventually the drivers
construct their list of available options from the macros defined in
the central option pool and the driver specific one.

const char driConfigurationOptions[] =
DRI_OPT_SECTION_DEBUG
        DRI_OPT_DEBUG_DMA(false)
DRI_OPT_SECTION_END
DRI_OPT_SECTION_TEXTURE
        DRI_OPT_PREFERRED_BPT("0,16,32",0)
DRI_OPT_END;

2.2.3 Character encoding

The XML 1.0 recommendation requires XML processors to support at least
the UTF-8 and UTF-16 encodings. UTF-8 is an ASCII compatible
multi-byte encoding which supports the entire Unicode character
set. Thus it is ideal as a single encoding for internationalized
descriptions including languages as different at English, Russian,
Greek, Korean, Chinese or Japanese. As the source files containing the
option definitions and their descriptions are processed by the C
compiler, the compiler would either have to understand input files in
UTF-8 encoding or a preprocessor has to translate a UTF-8 encoded
option library converting non-ASCII and multi-byte characters in
string literals to series of C string escape sequences. The goal is to
make sure that the resulting object file contains the available
options and descriptions in UTF-8 encoding.

So far I haven't been able to find much information about encoding
support in gcc. However, for the sake of portability the second
options seems preferable.

2.2.4 Obtaining option descriptions from a driver

The basic functionality for acquiring descriptions of configuration
options will be implemented in libGL. Applications can use
glXGetProcAddress to obtain the addresses of the new functions:

char *libglGetScreenDriver (Display *dpy, int screen);
char *libglGetDriverConfiguration (const char *drivername);

libglGetScreenDriver requires a local X connection in order to
determine the client side driver associated with screen.
libglGetDriverConfiguration can be called without an X connection. The
functions will be implemented in xc/lib/GL/dri/dri_glx.c, the same
file in which the loading of client side drivers is implemented. Most
of the necessary code is already there.

libglGetScreenDriver uses the DRI Xserver extension to obtain the name
of the client side driver for screen. libglGetDriverConfiguration
dlopens the driver and locates the XML document that describes
available configuration options using dlsym. The document is copied
into a newly allocated buffer before the driver is dlclosed. The
address of the buffer is returned to the application. In case of
failure NULL is returned. The application has to take care of freeing
the memory when it is no longer needed.

2.2.5 Command line tool for dumping XML option descriptions

A small command line program will make the functionality of
libglGetScreenDriver and libglGetDriverConfiguration available to
command line users and to GUIs written in a scripting language that
cannot use libGL directly. The command line tool must be able to work
with and without a local X connection. The following operations must
be supported:

 1. get the number of screens on the current display
 2. get the driver name for a given screen
 3. dump the configuration of the driver on a given screen
 4. dump the configuration of a driver given a driver name

Without a local X connection only (4) will be available. (3) is
redundant but a convenience that is easy enough to implement.

Synopsis: xdriinfo [ nscreens | driver <screen> | options <screen or driver> ]

If called without an argument it lists the direct rendering capability
and, if it is dri capable, the driver name for each screen.

2.3 Validation

XML distinguishes between well-formed and valid XML documents. All XML
processors verify that a document is well-formed. Only validating XML
processors verify the validity of a document with respect to a DTD.
Expat, the XML processor included in XFree86, is non-validating.

Therefore the correct order and nesting of elements and the use of
valid attributes has to be checked by the driver or the GUI that reads
a configuration file or an XML document describing available
options. There are three choices how to handle unknown elements or
attributes and character data: 1) ignore, 2) warning, 3) error.
Unknown data in the configuration file should probably cause a
warning. If the driver finds unknown data in the XML document
describing the driver's options it should indicate a fatal error. Data
type and range checking of option values has to be implemented based
on the information provided by the drivers.

2.4 Where and when to read the configuration

There are two options when to read the configuration file. It could be
done right after libGL loaded the DRI driver. Alternatively it could
be read when a context is created. As the best place for caching the
configuration options seems to be the OpenGL context I prefer reading
the configuration on context creation. This would also allow an
external utility to test a new configuration online. It would save the
configuration, destroy its OpenGL context and create a new one which
would automatically use the new configuration.

In either case any behavior before the driver is loaded cannot be
influenced by configuration options. This includes the environment
variables LIBGL_ALWAYS_INDIRECT and LIBGL_DEBUG in the current
implementation.

Reading and verifying the configuration can be done driver
independently. All necessary information is contained in the
driver-specific option list. The necessary source files could live in
xc/lib/GL/mesa/src/drv/common. The configuration reading routine could
be invoked by the driver's context creation function. A configuration
cache would be contained in the driver context. All this can be done
without touching the Mesa source code.

2.5 Selecting the correct sections from configuration files

There should be a system wide configuration in /etc and user-specific
configuration files in the users' home directories. The configuration
files themselves will be structured in nested sections which contain
options specific to a particular device or a set of applications.

When the configuration is parsed options from all sections matching
the current situation would be read. All other ones are skipped
including all their subsections. If the same option is specified and
read more than once then the one read last will apply. Options read
from a user-specific configuration file override the system wide
configuration.

Technically there is no limit to the order or depth of nesting of
device and application sections from the driver's point of view. It
may however be a good idea to enforce limitations in order to allow
configuration GUIs to present the configuration in a simple way. The
most sensible ordering for systems which have generally only few
pieces of graphics hardware but many applications installed would be
to have device sections on the top level with nested application
specific sections. Allowing the opposite order of nesting would not
add more power to the configuration files. It would only be a matter
convenience for very rare setups with many different graphics devices.

The conventions used in the example configuration file in section 2.1
can be summarized like this:

- On the top level there are only device sections.

- A device section without a screen or driver attribute applies to all
  devices.

- Device sections contain only application sections.

- Application sections without an executable attribute apply to all
  applications.

- Only application sections can contain options.

2.6 How to query configuration options inside the driver

The configuration is cached in an opaque data type driConfigCache. A
set of functions for querying options of different types will be
exported to the drivers with naming conventions similar to OpenGL
functions:

  GLint driQueryOptioni (const driConfigCache *config, const char *name);
  GLfloat driQueryOptionf (const driConfigCache *config, const char *name);
  ...

If a configuration option was not specified in the configuration file
then these functions would return the default value given in
driConfigurationOptions. If an option's type and the function used
don't match or if a queried option is not defined at all an assertion
should fail in order to enforce consistency as to how options are
advertised and used.

The driQueryOption* calls would obviously be rather expensive as they
have to find an option given a string as a key, even if some
intelligent hashing algorithm is used. Therefore they should not be
used in inner loops. If an option has to be accessed very frequently
it is better to query the option once during context creation and
store the value in a variable in the driver context in the same way as
environment variables are handled now.

3. Issues
---------

3.1 Are there better keys for device sections in the config file than
  "screen" and "driver"? How would the driver and the GUI associate
  the key with a driver name?

One idea was to use the device identifier from XF86Config-4. However,
with the current DRI extension there is no way to find the driver name
associated with a device identifier.

3.2 Do we need more data types than int, float and bool?

3.3 Someone with experience in internationalization should comment on
  section 2.2.3. What about gcc and character encodings?

3.4 Nesting of device and application sections. Flexibility vs. Simplicity

See section 2.5.

3.5 Where would the DTDs be stored so that they are available to the
  driver and the GUI?

Closed. Expat is non-validating, so we don't need DTDs.

3.6 Common options

We should decide on an initial pool of common options which should be
implemented in all driver if supported by the respective
hardware. Having an initial pool of common options would also avoid
uncontrolled growth of driver-specific option pools in early stages.

3.7 Internals of the parser and the option cache

This is really an implementation issue with low priority for now. Just
pointing out that we haven't thought about it yet.

4. Revision History
------------------

2003/02/19  First public version

2003/03/05  Revision 1
   - Reading drivers' XML option description in libGL
   - Command line tool xdriinfo
   - XML terminology
   - Expat instead of libxml
   - Less subjunctive

References
----------

Larry Mongin    An XML primer
(http://www.bloomington.in.us/~mongin/xml-tutorial/index.htm)

The Expat XML Parser
(http://expat.sourceforge.net)

LibXML Website
(http://www.libxml.org)

W3C Recommendation
Extensible Markup Language (XML) 1.0 (Second Edition)
(http://www.w3.org/TR/2000/REC-xml-20001006)

DRI Website
(http://dri.sourceforge.net)

ARB_get_proc_address
(http://oss.sgi.com/projects/ogl-sample/registry/ARB/get_proc_address.txt)

Reply via email to