Skip to content

Commit

Permalink
Lots of refactoring, new api
Browse files Browse the repository at this point in the history
  • Loading branch information
nyurik committed Feb 9, 2025
1 parent a897c07 commit 3dd504f
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 132 deletions.
65 changes: 30 additions & 35 deletions platform/rust/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ use std::{env, fs};
use build_support::parse_deps;
use walkdir::WalkDir;

trait CfgBool {
fn define_bool(&mut self, key: &str, value: bool);
}

impl CfgBool for cmake::Config {
fn define_bool(&mut self, key: &str, value: bool) {
self.define(key, if value { "ON" } else { "OFF" });
}
}

/// Helper that returns a new cmake::Config with common settings.
/// It selects the renderer based on Cargo features: the user must enable exactly one of:
/// "metal", "opengl", or "vulkan". If none are explicitly enabled, on iOS/macOS the default is metal,
Expand All @@ -13,44 +23,29 @@ fn create_cmake_config(project_root: &Path) -> cmake::Config {
cfg.generator("Ninja");
cfg.define("CMAKE_C_COMPILER_LAUNCHER", "ccache");
cfg.define("CMAKE_CXX_COMPILER_LAUNCHER", "ccache");
cfg.define("MLN_DRAWABLE_RENDERER", "ON");
cfg.define("MLN_WITH_OPENGL", "OFF");
cfg.define_bool("MLN_DRAWABLE_RENDERER", true);
cfg.define_bool("MLN_WITH_OPENGL", false);

let (metal_enabled, opengl_enabled, vulkan_enabled) = {
let metal = env::var("CARGO_FEATURE_METAL").is_ok();
let opengl = env::var("CARGO_FEATURE_OPENGL").is_ok();
let vulkan = env::var("CARGO_FEATURE_VULKAN").is_ok();
if !metal && !opengl && !vulkan {
if cfg!(target_os = "ios") || cfg!(target_os = "macos") {
(true, false, false)
} else {
(false, false, true)
}
let with_opengl = env::var("CARGO_FEATURE_OPENGL").is_ok();
let mut with_metal = env::var("CARGO_FEATURE_METAL").is_ok();
let mut with_vulkan = env::var("CARGO_FEATURE_VULKAN").is_ok();

if !with_opengl && !with_metal && !with_vulkan {
if cfg!(any(target_os = "ios", target_os = "macos")) {
with_metal = true;
} else {
(metal, opengl, vulkan)
with_vulkan = true;
}
};

let num_enabled = (metal_enabled as u8) + (opengl_enabled as u8) + (vulkan_enabled as u8);
if num_enabled > 1 {
panic!("Features 'metal', 'opengl', and 'vulkan' are mutually exclusive. Please enable only one.");
}

if opengl_enabled {
cfg.define("MLN_WITH_OPENGL", "ON");
cfg.define("MLN_WITH_METAL", "OFF");
cfg.define("MLN_WITH_VULKAN", "OFF");
} else if metal_enabled {
cfg.define("MLN_WITH_OPENGL", "OFF");
cfg.define("MLN_WITH_METAL", "ON");
cfg.define("MLN_WITH_VULKAN", "OFF");
} else if vulkan_enabled {
cfg.define("MLN_WITH_OPENGL", "OFF");
cfg.define("MLN_WITH_METAL", "OFF");
cfg.define("MLN_WITH_VULKAN", "ON");
if ((with_metal as u8) + (with_opengl as u8) + (with_vulkan as u8)) > 1 {
panic!("Features 'metal', 'opengl', and 'vulkan' are mutually exclusive. Please enable only one.");
}

cfg.define("MLN_WITH_WERROR", "OFF");
cfg.define_bool("MLN_WITH_OPENGL", with_opengl);
cfg.define_bool("MLN_WITH_METAL", with_metal);
cfg.define_bool("MLN_WITH_VULKAN", with_vulkan);
cfg.define_bool("MLN_WITH_WERROR", false);
cfg
}

Expand All @@ -73,13 +68,12 @@ fn main() {
.unwrap_or_else(|_| panic!("Failed to read {}", deps_file.display()));

// Parse the deps file into a list of Cargo instructions.
let instructions = parse_deps(&deps_contents, &deps_build_dir.join("build"));
for instr in instructions {
println!("{}", instr);
for instr in parse_deps(&deps_contents, &deps_build_dir.join("build")) {
println!("{instr}");
}

// ------------------------------------------------------------------------
// 2. Build the actual "mbgl-core" target.
// 2. Build the actual "mbgl-core" static library target.
// ------------------------------------------------------------------------
let core_build_dir = create_cmake_config(&project_root)
.build_target("mbgl-core")
Expand All @@ -93,6 +87,7 @@ fn main() {
// ------------------------------------------------------------------------
// 3. Gather include directories and build the C++ bridge using cxx_build.
// ------------------------------------------------------------------------
// TODO: This is a temporary solution. We should get this list from CMake as well.
let mut include_dirs = vec![
project_root.join("include"),
project_root.join("platform/default/include"),
Expand Down
16 changes: 8 additions & 8 deletions platform/rust/build_support/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,18 @@ use std::path::Path;
pub fn parse_deps(deps_contents: &str, static_lib_base: &Path) -> Vec<String> {
let mut instructions = Vec::new();
let mut added_search_paths = HashSet::new();
let tokens: Vec<&str> = deps_contents.split_whitespace().collect();
let mut token_iter = tokens.iter().peekable();
let mut token_iter = deps_contents.split_whitespace().peekable();

while let Some(&token) = token_iter.next() {
while let Some(token) = token_iter.next() {
if token == "-framework" {
if let Some(&framework) = token_iter.next() {
instructions.push(format!("cargo:rustc-link-lib=framework={}", framework));
if let Some(framework) = token_iter.next() {
instructions.push(format!("cargo:rustc-link-lib=framework={framework}"));
} else {
panic!("Expected a framework name after '-framework'");
}
} else if token.starts_with("-l") {
let libname = &token[2..];
instructions.push(format!("cargo:rustc-link-lib={}", libname));
instructions.push(format!("cargo:rustc-link-lib={libname}"));
} else if token.ends_with(".a") {
let lib_path = Path::new(token);
let file_stem = lib_path.file_stem().expect("Library file has no stem");
Expand All @@ -41,9 +40,10 @@ pub fn parse_deps(deps_contents: &str, static_lib_base: &Path) -> Vec<String> {
search_dir.display()
));
}
instructions.push(format!("cargo:rustc-link-lib=static={}", lib_name));
instructions.push(format!("cargo:rustc-link-lib=static={lib_name}"));
} else {
instructions.push(format!("cargo:rustc-link-arg={}", token));
// FIXME: should not use args by default, maybe with a feature flag?
instructions.push(format!("cargo:rustc-link-arg={token}"));
}
}
instructions
Expand Down
8 changes: 3 additions & 5 deletions platform/rust/src/bin/render.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::fs;

use clap::Parser;
use maplibre_native::MapRenderer;
use maplibre_native::ImageRendererOptions;

/// MapLibre Native render tool
#[derive(Parser, Debug)]
Expand Down Expand Up @@ -79,9 +79,7 @@ fn main() {
// let val = s.source_version_prefix();
// println!("Parsed arguments: {:?}", val);

let mut map = MapRenderer::new();
map.set_size(512, 512);
let data = map.render();

let mut map = ImageRendererOptions::new().build_static_renderer();
let data = map.render_static(512, 512);
fs::write("out.png", data.as_slice()).unwrap();
}
68 changes: 0 additions & 68 deletions platform/rust/src/deps_parser.rs

This file was deleted.

2 changes: 1 addition & 1 deletion platform/rust/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
mod map_renderer;
mod tile_server_options;

pub use map_renderer::MapRenderer;
pub use map_renderer::{ImageRenderer, ImageRendererOptions, Static, Tile, Image};
pub use tile_server_options::TileServerOptions;

#[cxx::bridge(namespace = "ml::bridge")]
Expand Down
64 changes: 49 additions & 15 deletions platform/rust/src/map_renderer.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,65 @@
use std::marker::PhantomData;
use cxx::{CxxVector, UniquePtr};

use crate::ffi;
use crate::ffi::MapRenderer_setSize;

/// Configuration options for a tile server.
pub struct MapRenderer(UniquePtr<ffi::MapRenderer>);
#[derive(Debug, Clone, Default)]
pub struct ImageRendererOptions {
pixel_ratio: f32,
}

impl MapRenderer {
/// Create a new default configuration
impl ImageRendererOptions {
pub fn new() -> Self {
Self(ffi::MapRenderer_new())
Self::default()
}

pub fn build_static_renderer(self) -> ImageRenderer<Static> {
ImageRenderer::new(self.pixel_ratio)
}

pub fn set_size(&mut self, width: u32, height: u32) -> &mut Self {
ffi::MapRenderer_setSize(self.0.pin_mut(), width, height);
self
pub fn build_tile_renderer(self) -> ImageRenderer<Static> {
ImageRenderer::new(self.pixel_ratio)
}
}

/// Internal state type to render a static map image.
pub struct Static;
/// Internal state type to render a map tile.
pub struct Tile;

/// Configuration options for a tile server.
pub struct ImageRenderer<State>(UniquePtr<ffi::MapRenderer>, PhantomData<State>);

impl<State> ImageRenderer<State> {
/// Private constructor.
fn new(_pixel_ratio: f32/*, mode: Mode*/) -> Self {
let map = ffi::MapRenderer_new();
// map.set_pixel_ratio(self.pixel_ratio);
// map.set_mode(self.mode);
Self(map, PhantomData)
}
}

pub fn render(&mut self) -> UniquePtr<CxxVector<u8>> {
ffi::MapRenderer_render(self.0.pin_mut())
impl ImageRenderer<Static> {
pub fn render_static(&mut self, width: u32, height: u32) -> Image {
MapRenderer_setSize(self.0.pin_mut(), width, height);
Image(ffi::MapRenderer_render(self.0.pin_mut()) )
}
}

impl Default for MapRenderer {
fn default() -> Self {
Self::new()
impl ImageRenderer<Tile> {
pub fn render_tile(&mut self, zoom: f64, x: u64, y: u64) -> Image {
MapRenderer_setSize(self.0.pin_mut(), 512, 512);
// TODO: set tile location
Image(ffi::MapRenderer_render(self.0.pin_mut()) )
}
}

#[cfg(test)]
mod tests {}
pub struct Image(UniquePtr<CxxVector<u8>>);

impl Image {
pub fn as_slice(&self) -> &[u8] {
self.0.as_ref().unwrap().as_slice()
}
}

0 comments on commit 3dd504f

Please sign in to comment.