RCCExtensions

From Qt Wiki
Jump to navigation Jump to search

Extending the Qt Resource System

The Qt resource system was designed to embed arbitrary files into the program executable (or library) and provide convenient access to the data using familiar interfaces (QFile) and using resource paths as identifiers.

This proposal suggests to add an extension mechanism the Qt resource system, to make it possible to optimize the resources for target environment specific conditions. For example an image handling extension could be used for embedded target platforms to replace the use of .png image files with a GPU specific texture compression file format, transparently for the developer. Another example is an extension that would react to .qml and .js files and compile them ahead of time into a more efficient binary representation, for embedding in the program executable.

Extensions to rcc consists of a command line tools as well a configuration file that's installed into a directory that rcc reads.

The configuration file tells rcc about the extension's capabilities in terms of acceptable input file formats, output formats and conversion options.

When rcc processes files specified in the .qrc files, it inspects the file name extensions as well as general attributes and delegates processing to the extension program according if the configuration matches.

It is not a goal to create a fully-fledged build system inside rcc. It is important to limit the functionality to only support common use-cases and avoid creating a generic build system that may also end up building your Linux kernel.

The following sections briefly outline some of the common anticipated use-cases for rcc extensions.

Simple filter processing

The simplest way of extending the resource system is to transform an input file to a new file format and ask the Qt resource system to embed that alternate format instead. The extension program acts as single pass filter.

The input to the extension program is

   (1) the path of the file in the virtual resource file system
   (2) the path of the input file on the real file system

Correspondingly, the output is

   (3) the potentially new file name of the converted resource in the
   resource system
   (4) the alternate content to embed in the program executable by rcc
   instead.

The configuration file for such a filter extension could look like this:

   {
       "name": "etc2-converter",
       "input-formats": ["png", "jpg"],
       "output-formats": "["etc1", "etc2"],
   }

Determining the output (3) and (4) is done by calling the extension program twice, once with the "process-file-name" sub-command and once with the "process-data" sub-command.

For the example with a texture compressor that replaces .png input files with .etc1 compressed textures, the two calls could look like this:

   rcc-extension-png process-file-name
       --resource-path="/path/in/resources.png"
       --local-file-path="/Users/qt/dev/something/photo.png"

prints

   /path/in/resources.etc1

on stdout. Then rcc calls

   rcc-extension-png process-data
       --resource-path="/path/in/resources.png"
       --local-file-path="/Users/qt/dev/something/photo.png"
       --output-file="/tmp/XZY1234"

and the extension program would write the etc1 compressed texture data into the provided temporary file. Finally rcc would embed that binary data in the program executable under the path provided in the first call.

Combined processing

A more advanced use-case for resource pre-processing is to combine multiple images into so-called atlas textures. This poses three additional requirements to the rcc extension mechanism:

   (1) The ability to process multiple files in one go, to determine
   which files are suitable for atlas embedding and which ones are not.
   (2) The ability to combine files of different formats (different
   file extension) into the same output.
   (3) The ability to replace the content of the original files in the
   future virtual file system with information that leads to the new
   location within the atlas.

The configuration file for such an atlas extension could look like this:

   {
       "name": "atlas-compressor",
       "input-formats": ["png", "jpg"],
       "output-formats": ["png", "jpg"],
       "combine-input": true,
       "provides-substitutes": true,
   }

Similarly to the single file conversion, rcc would call the atlas compressor first to determine the file mapping:

   rcc-extension-atlas process-file-names
       --resource-paths=/path/to/temporary/file_with_all_matching_file_paths.txt
       --local-file-paths=/path/to/temporary/file_with_all_matching_real_paths.txt

prints first the virtual file name of the atlas file, followed by all the files that are part of the atlas:

   atlas1.png
   smallimage1.png
   anotherphoto2.png
   thirdonefitsaswell.png

If the compressor decides to produce multiple atlas files, two newlines are used to separate the different atlas files and their group. So the output could continue with two newlines, followed by

   atlas2.png
   image4.png
   image5.png

and finally any files for which the atlas compressor decides that they are not suitable, the output shall be two newlines followed by a single dash, a newline and the remaining file names:

   -
   doesnotfintintoatlas.png
   notsuitedeither.png

Based on this output, rcc can determine the groups of files that belong into an atlas and call the atlas compressor again for each group:

   rcc-extension-atlas process-data
       --file-group=/path/to/file_with_output_of_first_group.txt
       --output-file="/tmp/XZY1234"
       --replacement-content="/tmp/5678XZY"

The output file shall be the encoded output file atlas image and the replacement content shall be textual separate with newline characters per file.


Target specific optimizations

There exists a need to configure certain defaults for the convenience of the user. For example a texture compression converter needs to know which type of format the target GPU supports. We need the ability for Qt to provide defaults as well as the possiblity for the developer to specify overrides.

The build system calling rcc shall pass the path to the target "makespec", where further configuration files can be located NO, this makes rcc build-system specific; Qbs will not use mkspecs in the long term, or they may at least be optional.</nowiki>

In addition variables such as symbolic name for the deployment target (such as QMAKE_IOS_DEPLOYMENT_TARGET) could be forwarded by the build system to the command line as --deployment-target="$VALUE_THAT_APPLIES" .

Native resource systems

Target platforms such as Apple platforms (macOS, iOS, tvOS, watchOS) provide the developer with a system similar to the Qt resource system that can take care of slicing the actual resource data depending on the target device automatically. For example on Apple platforms the asset catalogs can be configured to group images for x2 and x3 screen resolutions accordingly, Apple transparently then slices the data at application installation time and the NSImage/UIImage API (for images), NSColor/UIColor (for colors), or NSDataAsset API (for other raw data files) provides the correctly sliced data transparently to the developer.

Automatic use of such facilities can be integrated into the Qt Resource System as an rcc extension by means of accessing external binary resource files via the native platform APIs.

The rcc compiler can be configured to produce different binary resource files for each requested flavor and use the native resource system to include these resource files accordingly. With macOS, iOS, tvOS, or watchOS as target, the slicing would then result in the production of an additional binary resource file (Assets.car) which gets deployed in the app bundle's resources directory, by producing an asset catalog containing a subset of the inputs and invoking the actool compiler to transform it, and the rcc asset catalog extension could provide rcc with the stub C++ loader code that would be compiled into the final executable (or as part of QtCore) that uses the native API to get hold of the binary resource file, image, or color. Finally that resource file data is registered with QResource::registerResource() and the data becomes available transparently to the Qt developer via the Qt resource system API.

Comments

Perhaps the file names in the resource system should never be replaceable. So the option of renaming as per the first example could be replaced with a simpler mechanism where the content of the original .png file is replaced with textual content (json?) that provides the names of the etc1 files to the QtQuick run-time.

Final notes

This draft is by no means intended to be a final specification. Instead it serves as material to iterate on, in order to refine for example the communication between rcc and the extension programs. Finally it can serve as input to the documentation for the rcc extension feature for the Qt documentation.