The Hummingbird HTML rendering engine’s architecture is based on tasks (also known as jobs). Units of work are dispatched to a task scheduler who runs them on different threads to maximize the resource usage of the hardware.
Hummingbird’s task system is very versatile. It allows developers to schedule tasks whose body is a C++ lambda and put them in different queues for processing. We decided from the inception of the system to try maximize the freedom of the developer when creating and using tasks. This freedom however can be dangerous when the lifetime and eventual data races between objects have to be taken into account.
Tasks conceptually (although the same in code) can be divided in two groups:
- “Simple” data-oriented tasks that execute some data transformation on an independent work group and have no side effects.
- High-level tasks that might arise from the interaction of multiple systems and objects with possibly complex lifetimes.
I definitely try to have as much work possible in the first type of tasks. A good example of such a task is the layout of a group of elements. The input data are POD structs with the styles needed for the element layout and the output are the positions of each element on the page.
High level tasks require an interaction with the lifetime of objects, possibly some of them are reference counted and usually can be accessed only in certain threads.
A particularly nasty error that arises from using reference counted objects is having them be destroyed in unexpected moments or threads.
In Hummingbird we try to encourage “simple” tasks and to make higher level ones tough to accidentally misuse. We introduced a compile-time checking system for task parameters. Classes can be marked to allow/disallow using their instances as task parameters. There are four ways for an object to be passed as a parameter in a task:
- Passing object by value. This is always OK in our system. The object passed will be a copy private to the task so it shouldn’t involve changing global or shared state. The object can still contain pointers as members or modify global state in a method but this is better caught in design or code reviews and has never caused errors in our code so far.
- Passing object by pointer. This is generally NOT OK. The system will not allow by default passing pointers unless they are explicitly marked by the programmer. Passing naked pointers to tasks is the source of most errors as the lifetime of said object is probably outside the task and there is a chance that object will be accessed concurrently. There is also the issue with the lifetime of the object, which is not well defined.
- Passing weak pointers. In the beginning we implicitly allowed this usage but recently made them require explicit marking as well.
Explicitly marking which classes are OK to be passed between tasks has several benefits:
- Forces the programmer to think twice about the lifetime and concurrent use of data.
- Helps in code reviews by signaling to reviewers that they should carefully inspect the usage of certain objects.
- Implies a contract for how the data will be used and self-documents the code.
- Avoids inadvertently passing wrong objects to tasks, which can happen due to the easy syntax provided by lambdas.
We have also added a mechanism to disallow passing a class to tasks altogether, even by value.
The implementation of the system is based on templates and some macros to make the syntax easy.
Creating a task is done in the following way:
The key here is the TASK_PARAMS, which validates each parameter. In the next blog post I’ll go into details on how the task validation mechanism is implemented.
On October 19 and 20 I had the amazing opportunity to take part in the W3C WebVR Workshop in San Jose. The event affirms VR as a major direction for the future of the web.
At Coherent Labs, we create HTML renderers so it was great to meet so many other browser developers that work on the same problems we do and share a similar mindset.
The first day, the event was scheduled to start and 8.30. I and my colleague George are in San Francisco, so this meant an early wake-up at 5 o’clock. After a succession of trolley bus, CalTrain and Uber we arrived at the Samsung offices in San Jose. The content more that paid off the early wake and travel.
I take the opportunity to thank Samsung for hosting the event and organizing it flawlessly with the W3C folks.
The event was packed with browser and VR developers including people from Mozilla, the Chrome team, Oculus, Samsung, Valve, the Edge team and many others. Everybody was really open to share ideas. Browser developer shared current state of VR support in their products along with their short-term release plans.
The workshop was divided in 2 days with the highlights being a starting and ending keynote, many “lightning” (5 minutes) talks and “breakout sessions” the second day. In breakout sessions different groups discussed ideas in many areas of VR integration with the web.
Of the lightning talks I was most interested in the one by Josh Carpenter from the Chrome team and the ones from Justin Rogers from Oculus. Josh shared his vision of the future of the web in VR, while Justin accented more on technical aspects and performance – many of the problems are similar to the ones we tackle in Coherent Labs’ products.
In the “breakout” sessions, I attended a very interesting one initiated by Tony Parisi (who is now Head of AR/VR at Unity) on an eventual future declarative 3D standard for the web. The idea was met with a lot of enthusiasm in the meeting, although people had different reasons they believed it was important. Half the people attending believe that it’ll ease authoring, a smaller percentage stressed the importance of homogeneity between platforms, while ~15% believe performance is the most important reason. Coming from game development I also voted for the performance reason.
The workshop ended with a recap and the commitment to reconvene soon (at least by W3C metrics ~ 1 year). All the materials from the meeting are public and available here.
The discussions identified many areas in which to work and there are still many open questions. WebVR requires writing a complete new website. While this might be feasible for new sites, it doesn’t solve the need to meaningfully display the billions of pages that are currently on the web. The DOM is still completely separated from the VR world so all the usual layout, styling etc. are still off-limits in VR.
Performance is an open problem, especially on mobile, where battery drain and overheating can make the experience particularly unpleasant for the user. The current browsers do a lot of things besides just rendering the scene and that can introduce stuttering and break immersion.
Last but not least, there is no solution for AR. Bringing all the AR-specifics – spatial interactions, real world elements etc. will be a real challenge in the following years.
The discussions opened some interesting questions for me personally as well. Our Hummingbird HTML renderer is super fast on mobile, equipping it with a WebVR renderer is a way forward that it will bring amazing benefits to VR users who will be able to stay immersed for longer and with better visuals.
Hummingbird scales great on modern mobile platforms, so overheating and stuttering will not happen.
Overall the W3C workshop was an eye-opening experience for me. The lion’s share of the work however is still ahead of us as a community. I’m very happy to be part of it!