RCCExtensions
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.
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. 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 iOS 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 iOS the asset catalogs can be configured to group images for x2 and x3 screen resolutions accordingly, Apple transparently then slices the data at application device installation time and the NSDataAsset API 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 external binary resource files.
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 iOS as target, the slicing would then result in the download of different binary resource files and the rcc ios asset catalog extension could provide rcc with the stub C++ loader code that would be compiled into the final executable that uses the NSDataAsset API to get hold of the binary resource file. 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.
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.