Thursday 4 October 2018

Performance Improvements for Omber

Omber's performance has always been slower than other vector drawing tools because

  • it can run in a web browser, and web browser code is slower than other code
  • it uses a custom graphics engine that I've written from scratch. Although this engine has support for Omber's gradients, it lacks many of the optimizations that are in older, more developed vector graphics engines
  • I've focused on adding features instead of on performance

This hasn't really been a problem for my uses because Omber defaults to a low quality mode that is fast enough to work with, and I can turn on the high quality HQ mode when I want a final image. I occasionally hire artists to give feedback about Omber, and I've been worried that they are initially confused by the low quality of Omber's default rendering. When they do find the HQ mode, they then tend to leave it on or they tend to regularly switch it on and off, meaning they experience sluggish performance when working.

This has worried me for a while, so I've decided to focus on improving Omber's performance enough that it can default to being in HQ mode. Below is a simulated animation of the different performance enhancements that I've made:


On the right is the original Omber. When you move a shape, it takes a while to draw, so it feels jerky and unresponsive. I spent a lot of time fixing up the performance of the initial drawing of shapes, so that Omber is responsive during shape manipulation. The middle animation demonstrates the effect of these performance improvements.

Omber also has a separate gradient generation stage that works in the background to generate gradients after you manipulate shapes. Since this runs in the background, it doesn't affect the responsiveness of Omber, so it usually isn't performance critical. Unfortunately, in HQ mode, the shapes that Omber has to deal with are more complicated, and the gradient generation started to become too slow for complex drawings. In the middle animation, you can see that after the shape has finished moving, it takes a while for the gradients to be calculated.

So I'm now working on improving gradient generation speed, so that Omber will behave like in the left animation, where it's responsive when you move a shape, and then the gradient quickly fills in afterwards.

The key to all these performance improvements is a new feature added to web browsers called Web Assembly. The existing Omber code has already been heavily optimized in the past. Unfortunately, in the past, web browsers could only run code written in JavaScript, and there are limitations to how fast those web browsers can run that code. WebAssembly lets browsers run code written in C++. This opens up many new possibilities for performance enhancements. C++ gives programmers more control over memory layouts, data types, and memory allocation. This makes it possible to rewrite key pieces of Omber code to make use of this extra control. For example, many of Omber's algorithms need to process thousands of points and triangles. With C++, these points and triangles can be stored compactly in arrays, which can be accessed more quickly and take less memory. Putting things in arrays also provides an arbitrary and implicit ordering on objects, providing a means to sort these objects. Supplementary information about these objects can be stored in arrays instead of dictionaries. Traditionally, the main problems with C++ is that it's hard to write and it's prone to security problems. I'm dealing the coding difficulties by focusing my efforts on only the small sections of code in Omber that take the most time. WebAssembly eliminates most security problems with C++ by adding extra security checks throughout the code.

As I've rewritten the slow parts of Omber in C++, I've also discovered a few coding mistakes that have reduced performance that I've eliminated. For example, I added some special code for handling some edge cases in the Edge web browser. Unfortunately, this resulted in mouse events being processed twice, halving performance.

These performance improvements will be released in the next week or two. After this round of optimizations, I think there are only limited means available for further speed-ups, such as taking advantage of increased parallelism (not really possible in web browsers) and algorithmic improvements (I have a few ideas in mind here, but those changes would require extensive new research).