Note: This is a cross-post from the Google Earth and Earth Engine Blog, written by Unfolded’s Ib Green and Ilija Puaca.
Google and Unfolded have partnered to develop an open source C++ version of deck.gl. An initial version supporting a limited subset of deck.gl layers and features is now freely available on GitHub.
Deck.gl is a widely used large-scale geospatial data visualization framework that has its roots in JavaScript and WebGL. The choice of JavaScript has served the deck.gl community well: Visualization is front-end computing and thus the browser is often the natural vehicle to reach users.
But there are cases where native implementation can provide better performance, user experience, and architectural fit, primarily in native mobile applications but also for certain high-performance computing use cases. It’s always been clear that a C++ version would enable new opportunities.
A few months ago, a collaboration with engineers working on Google Earth allowed us to fine-tune the architectural vision for deck.gl-native
. The goal was to prototype new deck.gl-powered visualization experiences in Google Earth across web (using WebAssembly), iOS, and Android platforms. A native solution was required to enable a high-performance integration with Google Earth’s rendering engine on all platforms. With our designs solidified, and a concrete use case in hand, we were ready to start building deck.gl in C++.
A new API that’s both familiar and efficient
The new deck.gl C++ API has been designed to correspond closely to the JavaScript API whenever that makes sense and performance is not sacrificed.
As can be seen in the sample code, familiar classes such as Deck
, ScatterplotLayer
, MapView
and ViewState
work just as a JavaScript deck.gl user would expect.
At the same time, layer accessor methods ( getPosition
and getFillColor
) that enable data-driven styling are now based on C++ lambda functions for maximum flexibility and performance.
auto layerProps = std::make_shared<ScatterplotLayer::Props>();
layerProps>getPosition = [](const Row &row) {
return row.getVector3<float>("position");
};
layerProps>getFillColor = [](const Row &row) {
return mathgl::Vector4<float>{255, 0, 0, 255};
};
layerProps>data = /* your dataset (arrow::Table) goes here */;
auto deckProps = std::make_shared<Deck::Props>();
deckProps->layers = {layerProps};
deckProps->initialViewState = std::make_shared<ViewState>();
deckProps->views = {std::make_shared<MapView>()};
auto deck = std::make_shared<Deck>(deckProps);
deck->run();
deck.gl-native C++ code that renders a ScatterplotLayer
with data-driven styling.
Software architecture of deck.gl-native
Implementing a sophisticated WebGL framework such as deck.gl from scratch in a new programming language (without the need to support backwards compatibility and all the specialized features deck.gl has accumulated on the JavaScript side) gave us the ability to take a fresh look at a number of foundational architectural choices.
For more information on deck.gl architecture, the deck.gl Technical Deep-Dive is a good read. While written for the JavaScript version of deck.gl, many concepts apply to the C++ port as well.
Apache Arrow
All in-memory table processing is based on the Apache Arrow C++ API, which provided significant performance advantages because tables are stored in a GPU-friendly columnar binary data layout.
Note that while Apache Arrow has a fairly sophisticated API, this will be almost invisible to deck.gl-native applications as long they use the loaders provided by deck.gl. CSV and JSON table loaders are provided as part of the deck.gl library in the initial version, and .arrow
tables can be loaded with the Arrow API.
Naturally, for advanced table processing use cases, applications are free to work directly with the Arrow API to build and process tables, and then pass resulting Arrow tables to deck.gl.
To get started with Arrow, useful resources might be:
- Arrow C++ API Docs
- Arrow Test Suite for examples of working code
Graphics backend: native WebGPU via Dawn
Deck.gl-native is being built on top of WebGPU API using the Dawn framework.
The Dawn framework is a C++ implementation of the WebGPU API and is a compelling choice for deck.gl-native:
- The JavaScript version of deck.gl will inevitably move from WebGL to WebGPU, so having both C++ and JavaScript work against a common 3D API will significantly increase the ease of aligning the JavaScript and C++ code bases.
- The Dawn project has the ambition to provide backends on basically all platforms/rendering APIs of interest, including Vulkan, Metal, D3D12, and OpenGL. This ideally means that deck.gl-native itself will only have to implement a single backend, namely Dawn.
Note that Dawn is still a work in progress (with different levels of support for different platforms; the prototype is only being tested on iOS), and there is some risk with this technology choice. However, given the momentum behind WebGPU in browsers, we feel that the prospects are currently looking good.
Future directions
Beyond mobile: workstations and servers
While the JavaScript version of deck.gl runs well in a mobile web view inside a native mobile application, this mode prevents application from sharing the WebGL context with other rendering engines and take full control of rendering.
Thus, a “native” C++ implementation of deck.gl is not only required to provide optimal user experience on mobile devices and through integrations with apps such as Google Earth for mobile; it also provides exciting integration opportunities with a number of advanced, high-performance (usually C++ based) software packages that are not available or performant in browsers. These could be math libraries, computer vision libraries, etc.
Workstations and servers sometimes provide better GPU capabilities than browsers can expose through WebGL, and a C++ deck.gl implementation opens the option to use more advanced GPU acceleration when specialized hardware is available, such as nVidia’s CUDA technology. The ideal setup would be that vis.gl automatically takes maximum advantage of the best hardware that it is available at run-time (whether WebGL, WebGPU or CUDA).
deck.gl as a cross-programming-language framework
With the addition of a native C++ implementation, deck.gl is taking another big step away from being a “JavaScript first” framework, moving towards becoming a multi-language visualization architecture, complementing pydeck (Python deck.gl bindings) and the completely declarative deck.gl JSON API.
For more information, see the deck.gl cross-platform architecture that describes approaches to keeping multi-language implementations of deck.gl compatible. It’s still a work-in-progress, but gives a sense of the higher level direction.
Additional loaders
CSV and JSON table loaders are provided as part of the deck.gl library. To support additional table formats, additional “loaders” can be implemented that load various formats and “convert” the loaded tables to Arrow representation. Integrations with other C++ libraries, such as GDAL for geospatial and imaging formats, are also interesting.
Acknowledgements
Unfolded would like to thank Google for support and encouragement in getting the deck.gl-native development started.
Links: