Using Unity’s ShaderVariantCollection

Recently I have been working on porting an existing Unity game to macOS. It is a shoot-em-up called Blue Rider developed by Ravegan from Córdoba, Argentina. It was originally released on PC (Steam), XBox, Playstation 4, and Switch.

Blue Rider Logo

The main things I needed to work on to bring Blue Rider to macOS were the menu system, the resolution handling, the input handling, and some optimizations to achieve a smooth framerate.

(Note: I’m using Unity 5.6.7f1 since Blue Rider was written using a 5.x version. I’m not 100% sure, but based on the current documentation, I think what I’m doing here still applies with recent versions.)

The Problem

One such optimization had to do with shaders. The game was hitching sometimes when an enemy appeared and when it exploded. It only seemed to happen some times and with some enemies.

I’ll explain what I found when I broke out the profiler and then I’ll provide one possible solution using ShaderVariantCollection.

Continue reading

Qt Patches: QGraphicsView & QImageWriter

QGraphicsView

Two and a half years ago I wrote about a UX bug with QGraphicsView where it would reset the selection in the view if you tried to extend it with a rubberband selection. I have been using those changes in the version of Qt I maintain for my software.

I finally took the time to figure out how to use the gerrit code review system for submitting patches to the Qt project, and worked with several other developers to get it in shape for merging into the codebase for Qt 5.5.

Qt Library

Qt Library

The way I implemented the changes in my old post was inelegant but functional, so I cleaned it up for submission. Then, based on suggestions from Andreas Hanssen, Dominik Haumann, and Thorbjørn Martsum, took it to the next level to make it elegant. I was even forced to add tests before it would be accepted! <gasp> (Thanks again guys!)

The changes will appear in Qt 5.5, but they will not be backported to Qt4. I have, however, created patches for both if you need to use them:

Qt4 Patch: QGraphicsView_Rubberband_Select_Qt4_patch.diff

Qt5 Patch: QGraphicsView_Rubberband_Select_Qt5_patch.diff


QImageWriter

I also revisited my patch from three years ago for QImageWriter which added the ability to turn on the optimize and progressive scan switches for writing JPEGs, which I also was maintaining in my own version of Qt.

This work had input from another developer, Gunnar Sletta, and became a better commit because of it (thanks Gunnar!).

These changes will also be part of Qt 5.5 and won’t be backported to Qt4. I have created patches for both Qt4 and Qt5 if you need them:

Qt4 Patch: QImageWriter_Qt4_patch.diff

Qt5 Patch: QImageWriter_Qt5_patch.diff


I hope these changes and patches are useful to someone out there. Based on this positive experience I hope to contribute more small changes I have lying around somewhere…

Running jpegtran From a Qt Application

Continuing on with my obsession with smaller images, I thought I’d give an example of how to include jpegtran with your Qt app and how to call it using QProcess to optimize jpegs. Why do this? The use-case I had was that I was downloading images from the net from within my application and I wanted to ensure that they were optimized. I could have read them in and used my modifications to QImageWriter & co. to write them back out, but we are dealing with JPEG which is a lossy format, so I wanted a lossless way to optimize the images.

Continue reading

QImageWriter and Writing JPEGs

If you are using the QImageWriter class in Qt to write JPEG files, you may have noticed that it creates large files.

For example, saving out a capture of a window in my app resulted in a 332 kB file. If I run that through ImageOptim [mentioned previously], this is reduced to 266 kB. Huh? What’s happening here?

Digging into the code, I looked at what jpegtran [which is what ImageOptim is running] did to reduce file size. It turns out there are two options you can turn on in libjpeg to reduce file size when writing out JPEGs: optimize and progressive scan. These are both lossless operations, so by turning both of these options on we can reduce the size of the image files without sacrificing any quality.

If I turn on just the optimize option, the file size reduces to 287 kB. Turning both optimize and progressive on reduces the files size to… 266 kB – the same as ImageOptim.

I should also note that writing PNGs using QImageWriter is almost useless given the size of the files it produces [at 100% quality]. The same window capture I mention above results in a 6.6 MB PNG! This can be reduced to a much more manageable 242 kB if you run it through ImageOptim. The problem is, unlike JPEG, the time to optimize a PNG is not trivial, so even if there are switches to do something similar, the time it takes to optimize would result in long delays writing out the PNG file. I haven’t fully investigated this, so there may yet be a solution.

To handle the JPEG issue, I filed a Qt report and patch: Support additional JPEG write options: ‘optimize’ and ‘progressive’ [QTBUG-20075].

The patch modifies the following files:

  • src/gui/image/qimageiohandler.cpp
  • src/gui/image/qimageiohandler.h
  • src/gui/image/qimagewriter.cpp
  • src/gui/image/qimagewriter.h
  • src/gui/image/qjpeghandler.cpp

It adds two options to the QImageWriter class: ImageOption::Optimize and ImageOption::Progressive. It is used like this:

Magic! Smaller JPEG files for free. I hope this patch will eventually make its way into the release version of Qt.

I can’t see any reason why the optimize option within libjpeg defaults to false in the first place – any ideas?

(19 Jan 2015): I submitted a patch for this which has been merged into the Qt codebase. This fix will be part of Qt 5.5.

ImageOptim

ImageOptim is a cool tool by Kornel Lesiński for Mac OS X used to optimize images. Why would I want to do that you ask? It reduces the size of images so they take up less disk space. This means if you are working on a website, it will load a little faster for your users. If you are working on games, it can reduce the amount of data being sent to the GPU which can speed up the loading of textures [make sure you are using lossless compression of course].

ImageOptim is a front-end to several image optimizing tools including AdvPNG, OptiPNG, Pngcrush, JpegOptim, jpegtran, and Gifsicle. It works on PNG, JPG, and GIF images.

ImageOptim Example

ImageOptim Example

Photoshop is especially bad at creating small files when it saves them. It’s incredible the number of images on the web that can be optimized to save everyone time and money. Anyone running a website should consider using ImageOptim or a tool like it on their images.