mirror of
https://github.com/maplibre/maplibre-rs.git
synced 2025-12-08 19:05:57 +00:00
Merge pull request #174 from maxammann/wasm-executor
* Experiment with single threaded executor * Avoid exiting process * Use custom profile and remove wasm-pack * Update run configs * Prepare JS lib * Remove run config * Disable geometry index * Conditionally enable multithreaded implementation * Add run config * Add conditional compilation * Introduce environment * Remove ScheduleMethod and replace with Scheduler * Introduce AsyncProcedureCall * Update run config * Add experiment for unsync scheduling * Always import memory * Add first working version which does not need shared memory on web * Fix linux CI script * Remove maximum memory limits * Fix multithreading in web * Fix tracy dependency versions * Run formatter * Add a lot of TODO notes * Deduplicate workflow for more demos * Fix formatting * Selectively install targets * Fix wasm-bindgen install * Do not build std lib by default * Restructure web module to include JS code for multithreaded and non-multithreaded * Make multithreading named consistantly * Add more jobs * Do not rebuild std on check and test * Mark functions unsafe * Add runner for wasm32 again * Fix check expression * Finish CI setup * Add type for the tag * Update documentation * Switch to TS config for webpack * Fix android checks
This commit is contained in:
commit
2696d8133b
@ -2,10 +2,20 @@
|
|||||||
rustflags = [
|
rustflags = [
|
||||||
# Enabled unstable APIs from web_sys
|
# Enabled unstable APIs from web_sys
|
||||||
"--cfg=web_sys_unstable_apis",
|
"--cfg=web_sys_unstable_apis",
|
||||||
# Enables features which are required for shared-memory
|
"-C", "link-args=--import-memory",
|
||||||
"-C", "target-feature=+atomics,+bulk-memory,+mutable-globals",
|
|
||||||
# Enables the possibility to import memory into wasm.
|
|
||||||
# Without --shared-memory it is not possible to use shared WebAssembly.Memory.
|
|
||||||
"-C", "link-args=--shared-memory --import-memory",
|
|
||||||
]
|
]
|
||||||
runner = 'wasm-bindgen-test-runner'
|
runner = 'wasm-bindgen-test-runner'
|
||||||
|
|
||||||
|
[profile.wasm-dev]
|
||||||
|
inherits = "dev"
|
||||||
|
opt-level = 's'
|
||||||
|
debug = true
|
||||||
|
debug-assertions = true
|
||||||
|
overflow-checks = true
|
||||||
|
panic = 'abort'
|
||||||
|
|
||||||
|
[profile.wasm-release]
|
||||||
|
inherits = "release"
|
||||||
|
opt-level = 's'
|
||||||
|
lto = true
|
||||||
|
panic = 'abort'
|
||||||
|
|||||||
2
.github/actions/cloudflare-deploy/action.yml
vendored
2
.github/actions/cloudflare-deploy/action.yml
vendored
@ -1,5 +1,5 @@
|
|||||||
name: deploy
|
name: deploy
|
||||||
description: Deploy on maxammann.org
|
description: Deploy on cloudflare
|
||||||
|
|
||||||
inputs:
|
inputs:
|
||||||
project:
|
project:
|
||||||
|
|||||||
2
.github/workflows/build-deploy-docs.yml
vendored
2
.github/workflows/build-deploy-docs.yml
vendored
@ -17,7 +17,7 @@ jobs:
|
|||||||
- uses: extractions/setup-just@v1
|
- uses: extractions/setup-just@v1
|
||||||
- name: Install toolchain
|
- name: Install toolchain
|
||||||
shell: bash
|
shell: bash
|
||||||
run: just default-toolchain
|
run: just stable-toolchain
|
||||||
- uses: Swatinem/rust-cache@v1
|
- uses: Swatinem/rust-cache@v1
|
||||||
- name: Setup mdBook
|
- name: Setup mdBook
|
||||||
uses: peaceiris/actions-mdbook@v1
|
uses: peaceiris/actions-mdbook@v1
|
||||||
|
|||||||
8
.github/workflows/demo-linux.yml
vendored
8
.github/workflows/demo-linux.yml
vendored
@ -12,14 +12,16 @@ jobs:
|
|||||||
- uses: extractions/setup-just@v1
|
- uses: extractions/setup-just@v1
|
||||||
- name: Install toolchain
|
- name: Install toolchain
|
||||||
shell: bash
|
shell: bash
|
||||||
run: just default-toolchain
|
run: |
|
||||||
|
just stable-toolchain
|
||||||
|
just stable-targets x86_64-unknown-linux-gnu
|
||||||
- uses: Swatinem/rust-cache@v1
|
- uses: Swatinem/rust-cache@v1
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
shell: bash
|
shell: bash
|
||||||
run: sudo apt-get install -y libwayland-dev libxkbcommon-dev # Required for winit
|
run: sudo apt-get install -y libwayland-dev libxkbcommon-dev # Required for winit
|
||||||
- name: Build
|
- name: Build
|
||||||
shell: bash
|
shell: bash
|
||||||
run: cargo build -p maplibre-demo
|
run: cargo build -p maplibre-demo --release --target x86_64-unknown-linux-gnu
|
||||||
- name: Check
|
- name: Check
|
||||||
shell: bash
|
shell: bash
|
||||||
run: just check maplibre-demo x86_64-unknown-linux-gnu
|
run: just check maplibre-demo x86_64-unknown-linux-gnu
|
||||||
@ -29,4 +31,4 @@ jobs:
|
|||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: maplibre-rs
|
name: maplibre-rs
|
||||||
path: target/x86_64-unknown-linux-gnu/debug/maplibre-demo
|
path: target/x86_64-unknown-linux-gnu/release/maplibre-demo
|
||||||
|
|||||||
6
.github/workflows/demo-macos.yml
vendored
6
.github/workflows/demo-macos.yml
vendored
@ -14,7 +14,9 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: Install toolchain
|
- name: Install toolchain
|
||||||
shell: bash
|
shell: bash
|
||||||
run: just default-toolchain
|
run: |
|
||||||
|
just stable-toolchain
|
||||||
|
just stable-targets x86_64-apple-darwin
|
||||||
- uses: Swatinem/rust-cache@v1
|
- uses: Swatinem/rust-cache@v1
|
||||||
- name: Build
|
- name: Build
|
||||||
shell: bash
|
shell: bash
|
||||||
@ -29,4 +31,4 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: maplibre-x86_64-apple-darwin-demo
|
name: maplibre-x86_64-apple-darwin-demo
|
||||||
path: apple/xcode/build/Build/Products/Debug/*.app
|
path: apple/xcode/build/Build/Products/Debug/*.app
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|||||||
6
.github/workflows/demo-windows.yml
vendored
6
.github/workflows/demo-windows.yml
vendored
@ -12,7 +12,9 @@ jobs:
|
|||||||
- uses: extractions/setup-just@v1
|
- uses: extractions/setup-just@v1
|
||||||
- name: Install toolchain
|
- name: Install toolchain
|
||||||
shell: bash
|
shell: bash
|
||||||
run: just default-toolchain
|
run: |
|
||||||
|
just stable-toolchain
|
||||||
|
just stable-targets x86_64-pc-windows-msvc
|
||||||
- uses: Swatinem/rust-cache@v1
|
- uses: Swatinem/rust-cache@v1
|
||||||
- uses: ilammy/msvc-dev-cmd@v1 # Provide access to lib.exe
|
- uses: ilammy/msvc-dev-cmd@v1 # Provide access to lib.exe
|
||||||
- name: Build
|
- name: Build
|
||||||
@ -28,4 +30,4 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: maplibre-x86_64-windows-demo
|
name: maplibre-x86_64-windows-demo
|
||||||
path: target/x86_64-pc-windows-msvc/release/maplibre-demo.exe
|
path: target/x86_64-pc-windows-msvc/release/maplibre-demo.exe
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|||||||
10
.github/workflows/library-android.yml
vendored
10
.github/workflows/library-android.yml
vendored
@ -12,7 +12,9 @@ jobs:
|
|||||||
- uses: extractions/setup-just@v1
|
- uses: extractions/setup-just@v1
|
||||||
- name: Install nightly toolchain
|
- name: Install nightly toolchain
|
||||||
shell: bash
|
shell: bash
|
||||||
run: just nightly-toolchain-android
|
run: |
|
||||||
|
just nightly-toolchain
|
||||||
|
just nightly-targets x86_64-linux-android aarch64-linux-android i686-linux-android
|
||||||
- uses: Swatinem/rust-cache@v1
|
- uses: Swatinem/rust-cache@v1
|
||||||
- name: Set NDK Version
|
- name: Set NDK Version
|
||||||
shell: bash
|
shell: bash
|
||||||
@ -30,15 +32,15 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
env "AR_x86_64-linux-android=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar" \
|
env "AR_x86_64-linux-android=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar" \
|
||||||
env "CC_x86_64-linux-android=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/x86_64-linux-android30-clang" \
|
env "CC_x86_64-linux-android=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/x86_64-linux-android30-clang" \
|
||||||
just check maplibre-android x86_64-linux-android
|
just nightly-check maplibre-android x86_64-linux-android ""
|
||||||
- name: Check aarch64
|
- name: Check aarch64
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
env "AR_aarch64-linux-android=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar" \
|
env "AR_aarch64-linux-android=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar" \
|
||||||
env "CC_aarch64-linux-android=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android30-clang" \
|
env "CC_aarch64-linux-android=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android30-clang" \
|
||||||
just check maplibre-android aarch64-linux-android
|
just nightly-check maplibre-android aarch64-linux-android ""
|
||||||
# FIXME: Requires cross-compilation
|
# FIXME: Requires cross-compilation
|
||||||
#- name: Test
|
#- name: Test
|
||||||
# shell: bash
|
# shell: bash
|
||||||
# # TODO: Additional test runs for different targets
|
# # TODO: Additional test runs for different targets
|
||||||
# run: just test maplibre-android aarch64-linux-android
|
# run: just test maplibre-android aarch64-linux-android
|
||||||
|
|||||||
4
.github/workflows/library-apple.yml
vendored
4
.github/workflows/library-apple.yml
vendored
@ -15,7 +15,9 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: Install toolchain
|
- name: Install toolchain
|
||||||
shell: bash
|
shell: bash
|
||||||
run: just default-toolchain
|
run: |
|
||||||
|
just stable-toolchain
|
||||||
|
just stable-targets x86_64-apple-darwin aarch64-apple-darwin x86_64-apple-ios aarch64-apple-ios aarch64-apple-ios-sim
|
||||||
- uses: Swatinem/rust-cache@v1
|
- uses: Swatinem/rust-cache@v1
|
||||||
- name: Build
|
- name: Build
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|||||||
81
.github/workflows/library-web.yml
vendored
81
.github/workflows/library-web.yml
vendored
@ -11,70 +11,58 @@ on:
|
|||||||
deploy:
|
deploy:
|
||||||
required: true
|
required: true
|
||||||
type: boolean
|
type: boolean
|
||||||
|
name:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
webgl:
|
||||||
|
required: true
|
||||||
|
type: boolean
|
||||||
|
multithreaded:
|
||||||
|
required: true
|
||||||
|
type: boolean
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
library-webgl:
|
build:
|
||||||
name: Build WebGL
|
name: Build
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: extractions/setup-just@v1
|
- uses: extractions/setup-just@v1
|
||||||
- name: Install nightly toolchain
|
- name: Install nightly toolchain
|
||||||
shell: bash
|
shell: bash
|
||||||
run: just nightly-toolchain
|
run: |
|
||||||
|
just nightly-toolchain
|
||||||
|
just nightly-targets wasm32-unknown-unknown
|
||||||
|
- name: Install rust sources (build-std)
|
||||||
|
if: inputs.multithreaded
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
just nightly-install-src
|
||||||
|
- name: Install wasm-bindgen
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
# Install wasm-bindgen with test runner
|
||||||
|
cargo install wasm-bindgen-cli # We want the latest version, as Cargo uses the latest version of wasm-bindgen
|
||||||
- uses: Swatinem/rust-cache@v1
|
- uses: Swatinem/rust-cache@v1
|
||||||
- name: Build lib
|
- name: Build lib
|
||||||
shell: bash
|
shell: bash
|
||||||
run: just web-lib build-webgl
|
run: just web-lib build --release ${{ inputs.webgl && '--webgl' || '' }} ${{ inputs.multithreaded && '--multithreaded' || '' }}
|
||||||
- name: Build demo
|
- name: Build demo
|
||||||
shell: bash
|
shell: bash
|
||||||
run: just web-demo build
|
run: just web-demo build
|
||||||
- name: Check
|
- name: Check
|
||||||
shell: bash
|
shell: bash
|
||||||
run: just web-check "web-webgl"
|
run: just nightly-check web wasm32-unknown-unknown ${{ inputs.webgl && 'web-webgl' || '""' }}
|
||||||
- name: Test
|
- name: Test
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: just web-test "web-webgl"
|
||||||
# Install test runner
|
|
||||||
cargo install wasm-bindgen-cli # We want the latest version, as Cargo uses the latest version of wasm-bindgen
|
|
||||||
just web-test "web-webgl"
|
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: webgl-demo
|
name: ${{ inputs.name }}
|
||||||
path: web/demo/dist/
|
|
||||||
|
|
||||||
library-webgpu:
|
|
||||||
name: Build WebGPU
|
|
||||||
runs-on: ubuntu-20.04
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- uses: extractions/setup-just@v1
|
|
||||||
- name: Install nightly toolchain
|
|
||||||
shell: bash
|
|
||||||
run: just nightly-toolchain
|
|
||||||
- uses: Swatinem/rust-cache@v1
|
|
||||||
- name: Build lib
|
|
||||||
shell: bash
|
|
||||||
run: just web-lib build
|
|
||||||
- name: Build demo
|
|
||||||
shell: bash
|
|
||||||
run: just web-demo build
|
|
||||||
- name: Check
|
|
||||||
shell: bash
|
|
||||||
run: just web-check ""
|
|
||||||
- name: Test
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
# Install test runner
|
|
||||||
cargo install wasm-bindgen-cli # We want the latest version, as Cargo uses the latest version of wasm-bindgen
|
|
||||||
just web-test ""
|
|
||||||
- uses: actions/upload-artifact@v2
|
|
||||||
with:
|
|
||||||
name: webgpu-demo
|
|
||||||
path: web/demo/dist/
|
path: web/demo/dist/
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
needs: [library-webgl, library-webgpu]
|
needs: [build]
|
||||||
if: inputs.deploy
|
if: inputs.deploy
|
||||||
name: Deploy
|
name: Deploy
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
@ -82,13 +70,10 @@ jobs:
|
|||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: actions/download-artifact@v2
|
- uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: webgl-demo
|
name: ${{ inputs.name }}
|
||||||
path: demo/webgl
|
path: demo
|
||||||
- uses: actions/download-artifact@v2
|
|
||||||
with:
|
|
||||||
name: webgpu-demo
|
|
||||||
path: demo/webgpu
|
|
||||||
- name: Set HTTP Headers for Cloudflare
|
- name: Set HTTP Headers for Cloudflare
|
||||||
|
if: inputs.multithreaded
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
echo "/*
|
echo "/*
|
||||||
@ -97,7 +82,7 @@ jobs:
|
|||||||
- name: Deploy
|
- name: Deploy
|
||||||
uses: ./.github/actions/cloudflare-deploy
|
uses: ./.github/actions/cloudflare-deploy
|
||||||
with:
|
with:
|
||||||
project: maplibre-rs-demos
|
project: ${{ inputs.name }}
|
||||||
source: demo
|
source: demo
|
||||||
CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
|
CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
|
||||||
CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
|
CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
|
||||||
|
|||||||
21
.github/workflows/on_main_push.yml
vendored
21
.github/workflows/on_main_push.yml
vendored
@ -24,9 +24,28 @@ jobs:
|
|||||||
secrets: inherit
|
secrets: inherit
|
||||||
library-android:
|
library-android:
|
||||||
uses: ./.github/workflows/library-android.yml
|
uses: ./.github/workflows/library-android.yml
|
||||||
library-web:
|
library-web-webgl:
|
||||||
uses: ./.github/workflows/library-web.yml
|
uses: ./.github/workflows/library-web.yml
|
||||||
with:
|
with:
|
||||||
|
name: maplibre-rs-demo-webgl
|
||||||
|
webgl: true
|
||||||
|
multithreaded: false
|
||||||
|
deploy: true
|
||||||
|
secrets: inherit
|
||||||
|
library-web-webgl-multithreaded:
|
||||||
|
uses: ./.github/workflows/library-web.yml
|
||||||
|
with:
|
||||||
|
name: maplibre-rs-demo-webgl-multithreaded
|
||||||
|
webgl: true
|
||||||
|
multithreaded: true
|
||||||
|
deploy: true
|
||||||
|
secrets: inherit
|
||||||
|
library-web-webgpu:
|
||||||
|
uses: ./.github/workflows/library-web.yml
|
||||||
|
with:
|
||||||
|
name: maplibre-rs-demo-webgpu
|
||||||
|
webgl: false
|
||||||
|
multithreaded: false
|
||||||
deploy: true
|
deploy: true
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
library-apple:
|
library-apple:
|
||||||
|
|||||||
19
.github/workflows/on_pull_request.yml
vendored
19
.github/workflows/on_pull_request.yml
vendored
@ -19,9 +19,26 @@ jobs:
|
|||||||
deploy: false
|
deploy: false
|
||||||
library-android:
|
library-android:
|
||||||
uses: ./.github/workflows/library-android.yml
|
uses: ./.github/workflows/library-android.yml
|
||||||
library-web:
|
library-web-webgl:
|
||||||
uses: ./.github/workflows/library-web.yml
|
uses: ./.github/workflows/library-web.yml
|
||||||
with:
|
with:
|
||||||
|
name: maplibre-rs-demo-webgl
|
||||||
|
webgl: true
|
||||||
|
multithreaded: false
|
||||||
|
deploy: false
|
||||||
|
library-web-webgl-multithreaded:
|
||||||
|
uses: ./.github/workflows/library-web.yml
|
||||||
|
with:
|
||||||
|
name: maplibre-rs-demo-webgl-multithreaded
|
||||||
|
webgl: true
|
||||||
|
multithreaded: true
|
||||||
|
deploy: false
|
||||||
|
library-web-webgpu:
|
||||||
|
uses: ./.github/workflows/library-web.yml
|
||||||
|
with:
|
||||||
|
name: maplibre-rs-demo-webgpu
|
||||||
|
webgl: false
|
||||||
|
multithreaded: false
|
||||||
deploy: false
|
deploy: false
|
||||||
library-apple:
|
library-apple:
|
||||||
uses: ./.github/workflows/library-apple.yml
|
uses: ./.github/workflows/library-apple.yml
|
||||||
|
|||||||
6
.github/workflows/run-benchmarks.yml
vendored
6
.github/workflows/run-benchmarks.yml
vendored
@ -12,7 +12,9 @@ jobs:
|
|||||||
- uses: extractions/setup-just@v1
|
- uses: extractions/setup-just@v1
|
||||||
- name: Install toolchain
|
- name: Install toolchain
|
||||||
shell: bash
|
shell: bash
|
||||||
run: just default-toolchain
|
run: |
|
||||||
|
just stable-toolchain
|
||||||
|
just stable-targets x86_64-unknown-linux-gnu
|
||||||
- uses: Swatinem/rust-cache@v1
|
- uses: Swatinem/rust-cache@v1
|
||||||
- name: Install GPU Drivers
|
- name: Install GPU Drivers
|
||||||
uses: ./.github/actions/install-driver
|
uses: ./.github/actions/install-driver
|
||||||
@ -20,4 +22,4 @@ jobs:
|
|||||||
uses: ./.github/actions/download-test-data
|
uses: ./.github/actions/download-test-data
|
||||||
- name: Benchmark
|
- name: Benchmark
|
||||||
shell: bash
|
shell: bash
|
||||||
run: WGPU_BACKEND=vulkan just benchmark
|
run: WGPU_BACKEND=vulkan just benchmark
|
||||||
|
|||||||
2
.github/workflows/run-checks.yml
vendored
2
.github/workflows/run-checks.yml
vendored
@ -12,7 +12,7 @@ jobs:
|
|||||||
- uses: extractions/setup-just@v1
|
- uses: extractions/setup-just@v1
|
||||||
- name: Install toolchain
|
- name: Install toolchain
|
||||||
shell: bash
|
shell: bash
|
||||||
run: just default-toolchain
|
run: just stable-toolchain
|
||||||
- uses: Swatinem/rust-cache@v1
|
- uses: Swatinem/rust-cache@v1
|
||||||
- name: Format
|
- name: Format
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|||||||
4
.github/workflows/run-tests.yml
vendored
4
.github/workflows/run-tests.yml
vendored
@ -12,7 +12,9 @@ jobs:
|
|||||||
- uses: extractions/setup-just@v1
|
- uses: extractions/setup-just@v1
|
||||||
- name: Install toolchain
|
- name: Install toolchain
|
||||||
shell: bash
|
shell: bash
|
||||||
run: just default-toolchain
|
run: |
|
||||||
|
just stable-toolchain
|
||||||
|
just stable-targets x86_64-unknown-linux-gnu
|
||||||
- uses: Swatinem/rust-cache@v1
|
- uses: Swatinem/rust-cache@v1
|
||||||
- name: Install GPU Drivers
|
- name: Install GPU Drivers
|
||||||
uses: ./.github/actions/install-driver
|
uses: ./.github/actions/install-driver
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="Build WASM" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
<configuration default="false" name="Build WASM (single-threaded)" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
||||||
<option name="command" value="build -p web --features web-webgl --lib --release --target wasm32-unknown-unknown -Z build-std=std,panic_abort" />
|
<option name="command" value="build -p web --features web-webgl --lib --profile wasm-dev --target wasm32-unknown-unknown" />
|
||||||
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||||
<option name="channel" value="DEFAULT" />
|
<option name="channel" value="DEFAULT" />
|
||||||
<option name="requiredFeatures" value="true" />
|
<option name="requiredFeatures" value="true" />
|
||||||
8
.idea/runConfigurations/Run_demo__debug_.xml
generated
8
.idea/runConfigurations/Run_demo__debug_.xml
generated
@ -1,6 +1,6 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="Run demo (debug " type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
<configuration default="false" name="Run demo (debug)" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
||||||
<option name="command" value="run -p maplibre-demo" />
|
<option name="command" value="run -p maplibre-demo -- headed" />
|
||||||
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||||
<option name="channel" value="DEFAULT" />
|
<option name="channel" value="DEFAULT" />
|
||||||
<option name="requiredFeatures" value="true" />
|
<option name="requiredFeatures" value="true" />
|
||||||
@ -9,7 +9,9 @@
|
|||||||
<option name="withSudo" value="false" />
|
<option name="withSudo" value="false" />
|
||||||
<option name="buildTarget" value="REMOTE" />
|
<option name="buildTarget" value="REMOTE" />
|
||||||
<option name="backtrace" value="SHORT" />
|
<option name="backtrace" value="SHORT" />
|
||||||
<envs />
|
<envs>
|
||||||
|
<env name="RUST_LOG" value="debug" />
|
||||||
|
</envs>
|
||||||
<option name="isRedirectInput" value="false" />
|
<option name="isRedirectInput" value="false" />
|
||||||
<option name="redirectInputPath" value="" />
|
<option name="redirectInputPath" value="" />
|
||||||
<method v="2">
|
<method v="2">
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="Run headed demo (debug+enable-tracing)" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
<configuration default="false" name="Run demo (debug+enable-tracing)" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
||||||
<option name="command" value="run -p maplibre-demo --features trace -- headed" />
|
<option name="command" value="run -p maplibre-demo --features trace -- headed" />
|
||||||
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||||
<option name="channel" value="DEFAULT" />
|
<option name="channel" value="DEFAULT" />
|
||||||
@ -1,5 +1,5 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="Run headed demo (release+enable-tracing)" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
<configuration default="false" name="Run demo (release+enable-tracing)" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
||||||
<option name="command" value="run -p maplibre-demo --release --features trace -- headed" />
|
<option name="command" value="run -p maplibre-demo --release --features trace -- headed" />
|
||||||
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||||
<option name="channel" value="DEFAULT" />
|
<option name="channel" value="DEFAULT" />
|
||||||
19
.idea/runConfigurations/Run_headless_demo__debug_enable_tracing__.xml
generated
Normal file
19
.idea/runConfigurations/Run_headless_demo__debug_enable_tracing__.xml
generated
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Run headless demo (debug+enable-tracing) " type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
||||||
|
<option name="command" value="run -p maplibre-demo --features trace -- headless" />
|
||||||
|
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||||
|
<option name="channel" value="DEFAULT" />
|
||||||
|
<option name="requiredFeatures" value="true" />
|
||||||
|
<option name="allFeatures" value="false" />
|
||||||
|
<option name="emulateTerminal" value="false" />
|
||||||
|
<option name="withSudo" value="false" />
|
||||||
|
<option name="buildTarget" value="REMOTE" />
|
||||||
|
<option name="backtrace" value="SHORT" />
|
||||||
|
<envs />
|
||||||
|
<option name="isRedirectInput" value="false" />
|
||||||
|
<option name="redirectInputPath" value="" />
|
||||||
|
<method v="2">
|
||||||
|
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
@ -20,7 +20,6 @@ lto = true
|
|||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
opt-level = 's'
|
opt-level = 's'
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
|
|
||||||
strip = "debuginfo"
|
strip = "debuginfo"
|
||||||
|
|
||||||
[profile.bench]
|
[profile.bench]
|
||||||
|
|||||||
@ -3,13 +3,11 @@ use std::ffi::CString;
|
|||||||
use jni::{objects::JClass, JNIEnv};
|
use jni::{objects::JClass, JNIEnv};
|
||||||
use log::Level;
|
use log::Level;
|
||||||
use maplibre::{
|
use maplibre::{
|
||||||
platform::{
|
platform::{http_client::ReqwestHttpClient, run_multithreaded, scheduler::TokioScheduler},
|
||||||
http_client::ReqwestHttpClient, run_multithreaded, schedule_method::TokioScheduleMethod,
|
|
||||||
},
|
|
||||||
render::settings::{Backends, WgpuSettings},
|
render::settings::{Backends, WgpuSettings},
|
||||||
MapBuilder,
|
MapBuilder,
|
||||||
};
|
};
|
||||||
use maplibre_winit::winit::WinitMapWindowConfig;
|
use maplibre_winit::winit::{run_headed_map, WinitMapWindowConfig};
|
||||||
|
|
||||||
#[cfg(not(target_os = "android"))]
|
#[cfg(not(target_os = "android"))]
|
||||||
compile_error!("android works only on android.");
|
compile_error!("android works only on android.");
|
||||||
@ -18,20 +16,8 @@ compile_error!("android works only on android.");
|
|||||||
pub fn android_main() {
|
pub fn android_main() {
|
||||||
env_logger::init_from_env(env_logger::Env::default().default_filter_or("info"));
|
env_logger::init_from_env(env_logger::Env::default().default_filter_or("info"));
|
||||||
|
|
||||||
run_multithreaded(async {
|
// TODO: Maybe requires: Some(Backends::VULKAN)
|
||||||
MapBuilder::new()
|
run_headed_map(None);
|
||||||
.with_map_window_config(WinitMapWindowConfig::new("maplibre android".to_string()))
|
|
||||||
.with_http_client(ReqwestHttpClient::new(None))
|
|
||||||
.with_schedule_method(TokioScheduleMethod::new())
|
|
||||||
.with_wgpu_settings(WgpuSettings {
|
|
||||||
backends: Some(Backends::VULKAN),
|
|
||||||
..WgpuSettings::default()
|
|
||||||
})
|
|
||||||
.build()
|
|
||||||
.initialize()
|
|
||||||
.await
|
|
||||||
.run()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
use maplibre::{
|
use maplibre::{
|
||||||
platform::{
|
io::apc::SchedulerAsyncProcedureCall,
|
||||||
http_client::ReqwestHttpClient, run_multithreaded, schedule_method::TokioScheduleMethod,
|
platform::{http_client::ReqwestHttpClient, run_multithreaded, scheduler::TokioScheduler},
|
||||||
},
|
|
||||||
MapBuilder,
|
MapBuilder,
|
||||||
};
|
};
|
||||||
use maplibre_winit::winit::{WinitEventLoop, WinitMapWindow, WinitMapWindowConfig, WinitWindow};
|
use maplibre_winit::winit::{
|
||||||
|
run_headed_map, WinitEnvironment, WinitEventLoop, WinitMapWindow, WinitMapWindowConfig,
|
||||||
|
WinitWindow,
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
|
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
|
||||||
compile_error!("apple works only on macOS and iOS.");
|
compile_error!("apple works only on macOS and iOS.");
|
||||||
@ -13,14 +15,5 @@ compile_error!("apple works only on macOS and iOS.");
|
|||||||
pub fn maplibre_apple_main() {
|
pub fn maplibre_apple_main() {
|
||||||
env_logger::init_from_env(env_logger::Env::default().default_filter_or("info"));
|
env_logger::init_from_env(env_logger::Env::default().default_filter_or("info"));
|
||||||
|
|
||||||
run_multithreaded(async {
|
run_headed_map(None);
|
||||||
MapBuilder::new()
|
|
||||||
.with_map_window_config(WinitMapWindowConfig::new("maplibre apple".to_string()))
|
|
||||||
.with_http_client(ReqwestHttpClient::new(None))
|
|
||||||
.with_schedule_method(TokioScheduleMethod::new())
|
|
||||||
.build()
|
|
||||||
.initialize()
|
|
||||||
.await
|
|
||||||
.run()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,7 +38,7 @@ fn parse_tile(c: &mut Criterion) {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.into_boxed_slice();
|
.into_boxed_slice();
|
||||||
ParseTile::default().process(
|
ParseTile::default().process(
|
||||||
(request, 0, data),
|
(request, data),
|
||||||
&mut PipelineContext::new(DummyPipelineProcessor),
|
&mut PipelineContext::new(DummyPipelineProcessor),
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
@ -58,7 +58,7 @@ fn tessellate_tile(c: &mut Criterion) {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.into_boxed_slice();
|
.into_boxed_slice();
|
||||||
let parsed = ParseTile::default().process(
|
let parsed = ParseTile::default().process(
|
||||||
(request, 0, data),
|
(request, data),
|
||||||
&mut PipelineContext::new(DummyPipelineProcessor),
|
&mut PipelineContext::new(DummyPipelineProcessor),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -4,16 +4,15 @@ use criterion::{criterion_group, criterion_main, Criterion};
|
|||||||
use maplibre::{
|
use maplibre::{
|
||||||
coords::{WorldTileCoords, ZoomLevel},
|
coords::{WorldTileCoords, ZoomLevel},
|
||||||
error::Error,
|
error::Error,
|
||||||
headless::{utils::HeadlessPipelineProcessor, HeadlessMapWindowConfig},
|
headless::{utils::HeadlessPipelineProcessor, HeadlessEnvironment, HeadlessMapWindowConfig},
|
||||||
io::{
|
io::{
|
||||||
|
apc::SchedulerAsyncProcedureCall,
|
||||||
pipeline::{PipelineContext, Processable},
|
pipeline::{PipelineContext, Processable},
|
||||||
source_client::HttpSourceClient,
|
source_client::HttpSourceClient,
|
||||||
tile_pipelines::build_vector_tile_pipeline,
|
tile_pipelines::build_vector_tile_pipeline,
|
||||||
TileRequest,
|
TileRequest,
|
||||||
},
|
},
|
||||||
platform::{
|
platform::{http_client::ReqwestHttpClient, run_multithreaded, scheduler::TokioScheduler},
|
||||||
http_client::ReqwestHttpClient, run_multithreaded, schedule_method::TokioScheduleMethod,
|
|
||||||
},
|
|
||||||
render::settings::{RendererSettings, TextureFormat},
|
render::settings::{RendererSettings, TextureFormat},
|
||||||
window::WindowSize,
|
window::WindowSize,
|
||||||
MapBuilder,
|
MapBuilder,
|
||||||
@ -22,19 +21,27 @@ use maplibre::{
|
|||||||
fn headless_render(c: &mut Criterion) {
|
fn headless_render(c: &mut Criterion) {
|
||||||
c.bench_function("headless_render", |b| {
|
c.bench_function("headless_render", |b| {
|
||||||
let mut map = run_multithreaded(async {
|
let mut map = run_multithreaded(async {
|
||||||
let mut map = MapBuilder::new()
|
let client = ReqwestHttpClient::new(None);
|
||||||
.with_map_window_config(HeadlessMapWindowConfig {
|
|
||||||
size: WindowSize::new(1000, 1000).unwrap(),
|
let mut map = MapBuilder::<
|
||||||
})
|
HeadlessEnvironment<_, _, _, SchedulerAsyncProcedureCall<_, _>>,
|
||||||
.with_http_client(ReqwestHttpClient::new(None))
|
>::new()
|
||||||
.with_schedule_method(TokioScheduleMethod::new())
|
.with_map_window_config(HeadlessMapWindowConfig {
|
||||||
.with_renderer_settings(RendererSettings {
|
size: WindowSize::new(1000, 1000).unwrap(),
|
||||||
texture_format: TextureFormat::Rgba8UnormSrgb,
|
})
|
||||||
..RendererSettings::default()
|
.with_http_client(client.clone())
|
||||||
})
|
.with_apc(SchedulerAsyncProcedureCall::new(
|
||||||
.build()
|
client,
|
||||||
.initialize_headless()
|
TokioScheduler::new(),
|
||||||
.await;
|
))
|
||||||
|
.with_scheduler(TokioScheduler::new())
|
||||||
|
.with_renderer_settings(RendererSettings {
|
||||||
|
texture_format: TextureFormat::Rgba8UnormSrgb,
|
||||||
|
..RendererSettings::default()
|
||||||
|
})
|
||||||
|
.build()
|
||||||
|
.initialize_headless()
|
||||||
|
.await;
|
||||||
|
|
||||||
map.map_schedule
|
map.map_schedule
|
||||||
.fetch_process(&WorldTileCoords::from((0, 0, ZoomLevel::default())))
|
.fetch_process(&WorldTileCoords::from((0, 0, ZoomLevel::default())))
|
||||||
|
|||||||
@ -11,7 +11,7 @@ module it can resolve WebAssembly files or WebWorkers dynamically.
|
|||||||
The following syntax is used to resolve referenced WebWorkers:
|
The following syntax is used to resolve referenced WebWorkers:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
new Worker(new URL("./pool.worker.ts", import.meta.url), {
|
new Worker(new URL("./multithreaded-pool.worker.ts", import.meta.url), {
|
||||||
type: 'module'
|
type: 'module'
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
@ -107,7 +107,7 @@ See config in `web/lib/build.mjs` for an example usage.
|
|||||||
### Babel & TypeScript
|
### Babel & TypeScript
|
||||||
|
|
||||||
Babel and TypeScript both can produce ESM modules, but they **fail with transforming references within the source code**
|
Babel and TypeScript both can produce ESM modules, but they **fail with transforming references within the source code**
|
||||||
like `new URL("./pool.worker.ts", import.meta.url)`. There exist some Babel plugins, but none of them is stable.
|
like `new URL("./multithreaded-pool.worker.ts", import.meta.url)`. There exist some Babel plugins, but none of them is stable.
|
||||||
Therefore, we actually need a proper bundler which supports outputting ESM modules.
|
Therefore, we actually need a proper bundler which supports outputting ESM modules.
|
||||||
The only stable solution to this is Parcel. Parcel also has good documentation around the bundling of WebWorkers.
|
The only stable solution to this is Parcel. Parcel also has good documentation around the bundling of WebWorkers.
|
||||||
|
|
||||||
@ -277,4 +277,4 @@ Example config in `package.json:
|
|||||||
|
|
||||||
### Rollup
|
### Rollup
|
||||||
|
|
||||||
Not yet evaluated
|
Not yet evaluated
|
||||||
|
|||||||
@ -102,18 +102,35 @@ click on run. This will start the MacOS application.
|
|||||||
|
|
||||||
## Web (WebGL, WebGPU)
|
## Web (WebGL, WebGPU)
|
||||||
|
|
||||||
If you have a browser which already supports a recent version of the WebGPU specification then you can start a
|
You need to first build the library for WebGL or WebGPU. Optionally, you can also enabled multi-threading support,
|
||||||
development server using the following commands.
|
which requires that the library is used in a secure environment:
|
||||||
|
[isSecureContext](https://developer.mozilla.org/en-US/docs/Web/API/isSecureContext)
|
||||||
|
and [crossOriginIsolated](https://developer.mozilla.org/en-US/docs/Web/API/crossOriginIsolated).
|
||||||
|
The demo runs this such an environment.
|
||||||
|
|
||||||
|
If you have a browser which already supports a recent version of the WebGPU specification then you can build the library
|
||||||
|
with WebGPU:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd web
|
just web-lib build # WebGPU
|
||||||
npm run start
|
|
||||||
```
|
```
|
||||||
|
|
||||||
If you want to run maplibre-rs with WebGL which is supported on every major browser, then you have to use the following
|
If not, then you must enable WebGL support:
|
||||||
command.
|
|
||||||
|
|
||||||
|
```bash
|
||||||
|
just web-lib build --webgl # WebGL
|
||||||
|
just web-lib build --webgl --multithreaded # WebGL + multithreaded
|
||||||
|
```
|
||||||
|
|
||||||
|
Instead of building it is also possible to watch for changes. The same flags like with `web-lib build` are supported:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
just web-lib watch --webgl
|
||||||
|
```
|
||||||
|
|
||||||
|
After building the library you can run the demo server:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
just web-lib build
|
|
||||||
just web-demo start
|
just web-demo start
|
||||||
```
|
```
|
||||||
|
|||||||
65
justfile
65
justfile
@ -5,15 +5,38 @@
|
|||||||
set shell := ["bash", "-c"]
|
set shell := ["bash", "-c"]
|
||||||
|
|
||||||
export NIGHTLY_TOOLCHAIN := "nightly-2022-07-03"
|
export NIGHTLY_TOOLCHAIN := "nightly-2022-07-03"
|
||||||
|
export STABLE_TOOLCHAIN := "1.62"
|
||||||
|
|
||||||
export CARGO_TERM_COLOR := "always"
|
export CARGO_TERM_COLOR := "always"
|
||||||
export RUST_BACKTRACE := "1"
|
export RUST_BACKTRACE := "1"
|
||||||
|
|
||||||
install-clippy:
|
|
||||||
rustup component add clippy
|
|
||||||
|
|
||||||
install-nightly-clippy:
|
stable-toolchain:
|
||||||
|
rustup toolchain install $STABLE_TOOLCHAIN
|
||||||
|
|
||||||
|
stable-targets *FLAGS:
|
||||||
|
rustup toolchain install $STABLE_TOOLCHAIN --target {{FLAGS}}
|
||||||
|
|
||||||
|
stable-install-clippy:
|
||||||
|
rustup component add clippy --toolchain $STABLE_TOOLCHAIN
|
||||||
|
|
||||||
|
|
||||||
|
nightly-toolchain:
|
||||||
|
rustup toolchain install $NIGHTLY_TOOLCHAIN
|
||||||
|
|
||||||
|
nightly-targets *FLAGS:
|
||||||
|
rustup toolchain install $NIGHTLY_TOOLCHAIN --target {{FLAGS}}
|
||||||
|
|
||||||
|
nightly-install-rustfmt: nightly-toolchain
|
||||||
|
rustup component add rustfmt --toolchain $NIGHTLY_TOOLCHAIN
|
||||||
|
|
||||||
|
nightly-install-src: nightly-toolchain
|
||||||
|
rustup component add rust-src --toolchain $NIGHTLY_TOOLCHAIN
|
||||||
|
|
||||||
|
nightly-install-clippy:
|
||||||
rustup component add clippy --toolchain $NIGHTLY_TOOLCHAIN
|
rustup component add clippy --toolchain $NIGHTLY_TOOLCHAIN
|
||||||
|
|
||||||
|
|
||||||
fixup:
|
fixup:
|
||||||
cargo clippy --no-deps -p maplibre --fix
|
cargo clippy --no-deps -p maplibre --fix
|
||||||
cargo clippy --allow-dirty --no-deps -p maplibre-winit --fix
|
cargo clippy --allow-dirty --no-deps -p maplibre-winit --fix
|
||||||
@ -27,36 +50,25 @@ fixup:
|
|||||||
cargo clippy --allow-dirty --no-deps -p maplibre-winit --target x86_64-linux-android --fix
|
cargo clippy --allow-dirty --no-deps -p maplibre-winit --target x86_64-linux-android --fix
|
||||||
cargo clippy --allow-dirty --no-deps -p maplibre-android --target x86_64-linux-android --fix
|
cargo clippy --allow-dirty --no-deps -p maplibre-android --target x86_64-linux-android --fix
|
||||||
|
|
||||||
check PROJECT ARCH: install-clippy
|
check PROJECT ARCH: stable-install-clippy
|
||||||
cargo clippy --no-deps -p {{PROJECT}} --target {{ARCH}}
|
cargo clippy --no-deps -p {{PROJECT}} --target {{ARCH}}
|
||||||
|
|
||||||
|
nightly-check PROJECT ARCH FEATURES: nightly-toolchain nightly-install-clippy
|
||||||
|
export RUSTUP_TOOLCHAIN=$NIGHTLY_TOOLCHAIN && cargo clippy --no-deps -p {{PROJECT}} --features "{{FEATURES}}" --target {{ARCH}}
|
||||||
|
|
||||||
test PROJECT ARCH:
|
test PROJECT ARCH:
|
||||||
cargo test -p {{PROJECT}} --target {{ARCH}}
|
cargo test -p {{PROJECT}} --target {{ARCH}}
|
||||||
|
|
||||||
benchmark:
|
benchmark:
|
||||||
cargo bench -p benchmarks
|
cargo bench -p benchmarks
|
||||||
|
|
||||||
install-rustfmt: nightly-toolchain
|
fmt: nightly-install-rustfmt
|
||||||
rustup component add rustfmt --toolchain $NIGHTLY_TOOLCHAIN
|
|
||||||
|
|
||||||
fmt: install-rustfmt
|
|
||||||
export RUSTUP_TOOLCHAIN=$NIGHTLY_TOOLCHAIN && cargo fmt
|
export RUSTUP_TOOLCHAIN=$NIGHTLY_TOOLCHAIN && cargo fmt
|
||||||
|
|
||||||
fmt-check: install-rustfmt
|
fmt-check: nightly-install-rustfmt
|
||||||
export RUSTUP_TOOLCHAIN=$NIGHTLY_TOOLCHAIN && cargo fmt -- --check
|
export RUSTUP_TOOLCHAIN=$NIGHTLY_TOOLCHAIN && cargo fmt -- --check
|
||||||
|
|
||||||
default-toolchain:
|
|
||||||
# Setups the toolchain from rust-toolchain.toml
|
|
||||||
cargo --version > /dev/null
|
|
||||||
|
|
||||||
nightly-toolchain:
|
|
||||||
rustup install $NIGHTLY_TOOLCHAIN
|
|
||||||
rustup component add rust-src --toolchain $NIGHTLY_TOOLCHAIN
|
|
||||||
|
|
||||||
nightly-toolchain-android: nightly-toolchain
|
|
||||||
rustup target add --toolchain $NIGHTLY_TOOLCHAIN x86_64-linux-android
|
|
||||||
rustup target add --toolchain $NIGHTLY_TOOLCHAIN aarch64-linux-android
|
|
||||||
rustup target add --toolchain $NIGHTLY_TOOLCHAIN i686-linux-android
|
|
||||||
|
|
||||||
web-install PROJECT:
|
web-install PROJECT:
|
||||||
cd web/{{PROJECT}} && npm install
|
cd web/{{PROJECT}} && npm install
|
||||||
@ -65,19 +77,16 @@ web-install PROJECT:
|
|||||||
# Example: just web-lib build-webgl
|
# Example: just web-lib build-webgl
|
||||||
# Example: just web-lib watch
|
# Example: just web-lib watch
|
||||||
# Example: just web-lib watch-webgl
|
# Example: just web-lib watch-webgl
|
||||||
web-lib TARGET: nightly-toolchain (web-install "lib")
|
web-lib TARGET *FLAGS: nightly-toolchain (web-install "lib")
|
||||||
export RUSTUP_TOOLCHAIN=$NIGHTLY_TOOLCHAIN && cd web/lib && npm run {{TARGET}}
|
export RUSTUP_TOOLCHAIN=$NIGHTLY_TOOLCHAIN && cd web/lib && npm run {{TARGET}} -- {{FLAGS}}
|
||||||
|
|
||||||
# Example: just web-demo start
|
# Example: just web-demo start
|
||||||
# Example: just web-demo build
|
# Example: just web-demo build
|
||||||
web-demo TARGET: (web-install "demo")
|
web-demo TARGET *FLAGS: (web-install "demo")
|
||||||
cd web/demo && npm run {{TARGET}}
|
cd web/demo && npm run {{TARGET}} -- {{FLAGS}}
|
||||||
|
|
||||||
web-check FEATURES: nightly-toolchain install-nightly-clippy
|
|
||||||
export RUSTUP_TOOLCHAIN=$NIGHTLY_TOOLCHAIN && cargo clippy --no-deps -p web --features "{{FEATURES}}" --target wasm32-unknown-unknown -Z build-std=std,panic_abort
|
|
||||||
|
|
||||||
web-test FEATURES: nightly-toolchain
|
web-test FEATURES: nightly-toolchain
|
||||||
export RUSTUP_TOOLCHAIN=$NIGHTLY_TOOLCHAIN && cargo test -p web --features "{{FEATURES}}" --target wasm32-unknown-unknown -Z build-std=std,panic_abort
|
export RUSTUP_TOOLCHAIN=$NIGHTLY_TOOLCHAIN && cargo test -p web --features "{{FEATURES}}" --target wasm32-unknown-unknown
|
||||||
|
|
||||||
#profile-bench:
|
#profile-bench:
|
||||||
# cargo flamegraph --bench render -- --bench
|
# cargo flamegraph --bench render -- --bench
|
||||||
|
|||||||
@ -10,7 +10,7 @@ readme = "../README.md"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
web-webgl = ["maplibre/web-webgl"]
|
web-webgl = ["maplibre/web-webgl"]
|
||||||
trace = ["maplibre/trace", "tracing-subscriber", "tracing-tracy", "tracy-client"]
|
trace = ["maplibre/trace"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
env_logger = "0.9.0"
|
env_logger = "0.9.0"
|
||||||
@ -19,10 +19,4 @@ maplibre-winit = { path = "../maplibre-winit", version = "0.0.1" }
|
|||||||
|
|
||||||
tile-grid = "0.3"
|
tile-grid = "0.3"
|
||||||
|
|
||||||
tracing = "0.1.35"
|
clap = { version = "3.2.12", features = ["derive"] }
|
||||||
tracing-subscriber = { version = "0.3.14", optional = true }
|
|
||||||
|
|
||||||
tracing-tracy = { version = "0.10", optional = true }
|
|
||||||
tracy-client = { version = "0.14", optional = true }
|
|
||||||
|
|
||||||
clap = { version = "3.2.12", features = ["derive"] }
|
|
||||||
|
|||||||
@ -1,16 +0,0 @@
|
|||||||
use maplibre::{
|
|
||||||
platform::{http_client::ReqwestHttpClient, schedule_method::TokioScheduleMethod},
|
|
||||||
MapBuilder,
|
|
||||||
};
|
|
||||||
use maplibre_winit::winit::WinitMapWindowConfig;
|
|
||||||
|
|
||||||
pub async fn run_headed() {
|
|
||||||
MapBuilder::new()
|
|
||||||
.with_map_window_config(WinitMapWindowConfig::new("maplibre".to_string()))
|
|
||||||
.with_http_client(ReqwestHttpClient::new(None))
|
|
||||||
.with_schedule_method(TokioScheduleMethod::new())
|
|
||||||
.build()
|
|
||||||
.initialize()
|
|
||||||
.await
|
|
||||||
.run()
|
|
||||||
}
|
|
||||||
@ -1,29 +1,37 @@
|
|||||||
use maplibre::{
|
use maplibre::{
|
||||||
coords::{LatLon, WorldTileCoords},
|
coords::{LatLon, WorldTileCoords},
|
||||||
error::Error,
|
error::Error,
|
||||||
headless::HeadlessMapWindowConfig,
|
headless::{HeadlessEnvironment, HeadlessMapWindowConfig},
|
||||||
platform::{http_client::ReqwestHttpClient, schedule_method::TokioScheduleMethod},
|
io::apc::SchedulerAsyncProcedureCall,
|
||||||
|
platform::{http_client::ReqwestHttpClient, scheduler::TokioScheduler},
|
||||||
render::settings::{RendererSettings, TextureFormat},
|
render::settings::{RendererSettings, TextureFormat},
|
||||||
util::grid::google_mercator,
|
util::grid::google_mercator,
|
||||||
window::WindowSize,
|
window::WindowSize,
|
||||||
MapBuilder,
|
MapBuilder,
|
||||||
};
|
};
|
||||||
|
use maplibre_winit::winit::WinitEnvironment;
|
||||||
use tile_grid::{extent_wgs84_to_merc, Extent, GridIterator};
|
use tile_grid::{extent_wgs84_to_merc, Extent, GridIterator};
|
||||||
|
|
||||||
pub async fn run_headless(tile_size: u32, min: LatLon, max: LatLon) {
|
pub async fn run_headless(tile_size: u32, min: LatLon, max: LatLon) {
|
||||||
let mut map = MapBuilder::new()
|
let client = ReqwestHttpClient::new(None);
|
||||||
.with_map_window_config(HeadlessMapWindowConfig {
|
let mut map =
|
||||||
size: WindowSize::new(tile_size, tile_size).unwrap(),
|
MapBuilder::<HeadlessEnvironment<_, _, _, SchedulerAsyncProcedureCall<_, _>>>::new()
|
||||||
})
|
.with_map_window_config(HeadlessMapWindowConfig {
|
||||||
.with_http_client(ReqwestHttpClient::new(None))
|
size: WindowSize::new(tile_size, tile_size).unwrap(),
|
||||||
.with_schedule_method(TokioScheduleMethod::new())
|
})
|
||||||
.with_renderer_settings(RendererSettings {
|
.with_http_client(client.clone())
|
||||||
texture_format: TextureFormat::Rgba8UnormSrgb,
|
.with_apc(SchedulerAsyncProcedureCall::new(
|
||||||
..RendererSettings::default()
|
client,
|
||||||
})
|
TokioScheduler::new(),
|
||||||
.build()
|
)) // FIXME (wasm-executor): avoid passing client and scheduler here
|
||||||
.initialize_headless()
|
.with_scheduler(TokioScheduler::new())
|
||||||
.await;
|
.with_renderer_settings(RendererSettings {
|
||||||
|
texture_format: TextureFormat::Rgba8UnormSrgb,
|
||||||
|
..RendererSettings::default()
|
||||||
|
})
|
||||||
|
.build()
|
||||||
|
.initialize_headless()
|
||||||
|
.await;
|
||||||
|
|
||||||
let tile_limits = google_mercator().tile_limits(
|
let tile_limits = google_mercator().tile_limits(
|
||||||
extent_wgs84_to_merc(&Extent {
|
extent_wgs84_to_merc(&Extent {
|
||||||
|
|||||||
@ -2,21 +2,12 @@ use std::io::ErrorKind;
|
|||||||
|
|
||||||
use clap::{builder::ValueParser, Parser, Subcommand};
|
use clap::{builder::ValueParser, Parser, Subcommand};
|
||||||
use maplibre::{coords::LatLon, platform::run_multithreaded};
|
use maplibre::{coords::LatLon, platform::run_multithreaded};
|
||||||
|
use maplibre_winit::winit::run_headed_map;
|
||||||
|
|
||||||
use crate::{headed::run_headed, headless::run_headless};
|
use crate::headless::run_headless;
|
||||||
|
|
||||||
mod headed;
|
|
||||||
mod headless;
|
mod headless;
|
||||||
|
|
||||||
#[cfg(feature = "trace")]
|
|
||||||
fn enable_tracing() {
|
|
||||||
use tracing_subscriber::{layer::SubscriberExt, Registry};
|
|
||||||
|
|
||||||
let subscriber = Registry::default().with(tracing_tracy::TracyLayer::new());
|
|
||||||
|
|
||||||
tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[clap(author, version, about, long_about = None)]
|
#[clap(author, version, about, long_about = None)]
|
||||||
#[clap(propagate_version = true)]
|
#[clap(propagate_version = true)]
|
||||||
@ -63,16 +54,14 @@ fn main() {
|
|||||||
env_logger::init_from_env(env_logger::Env::default().default_filter_or("info"));
|
env_logger::init_from_env(env_logger::Env::default().default_filter_or("info"));
|
||||||
|
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
enable_tracing();
|
maplibre::platform::trace::enable_tracing();
|
||||||
|
|
||||||
let cli = Cli::parse();
|
let cli = Cli::parse();
|
||||||
|
|
||||||
// You can check for the existence of subcommands, and if found use their
|
// You can check for the existence of subcommands, and if found use their
|
||||||
// matches just as you would the top level cmd
|
// matches just as you would the top level cmd
|
||||||
match &cli.command {
|
match &cli.command {
|
||||||
Commands::Headed {} => {
|
Commands::Headed {} => run_headed_map(None),
|
||||||
run_multithreaded(async { run_headed().await });
|
|
||||||
}
|
|
||||||
Commands::Headless {
|
Commands::Headless {
|
||||||
tile_size,
|
tile_size,
|
||||||
min,
|
min,
|
||||||
|
|||||||
@ -21,5 +21,5 @@ wasm-bindgen-futures = "0.4.31"
|
|||||||
maplibre = { path = "../maplibre", version = "0.0.2" }
|
maplibre = { path = "../maplibre", version = "0.0.2" }
|
||||||
winit = { version = "0.27.2", default-features = false }
|
winit = { version = "0.27.2", default-features = false }
|
||||||
cgmath = "0.18.0"
|
cgmath = "0.18.0"
|
||||||
instant = { version = "0.1.12", features = ["wasm-bindgen"] } # FIXME: Untrusted dependency
|
instant = { version = "0.1.12", features = ["wasm-bindgen"] } # TODO: Untrusted dependency
|
||||||
log = "0.4.17"
|
log = "0.4.17"
|
||||||
|
|||||||
@ -71,9 +71,9 @@ impl UpdateState for QueryHandler {
|
|||||||
&inverted_view_proj,
|
&inverted_view_proj,
|
||||||
false,
|
false,
|
||||||
) {
|
) {
|
||||||
|
// TODO reenable
|
||||||
/*state
|
/*state
|
||||||
.scheduler()
|
.scheduler()
|
||||||
.schedule_method()
|
|
||||||
.schedule(state.scheduler(), move |thread_local| async move {
|
.schedule(state.scheduler(), move |thread_local| async move {
|
||||||
if let Some(geometries) = thread_local.query_point(
|
if let Some(geometries) = thread_local.query_point(
|
||||||
&WorldCoords {
|
&WorldCoords {
|
||||||
|
|||||||
@ -1,7 +1,15 @@
|
|||||||
|
use std::{cell::RefCell, marker::PhantomData, ops::Deref, rc::Rc};
|
||||||
|
|
||||||
use instant::Instant;
|
use instant::Instant;
|
||||||
use maplibre::{
|
use maplibre::{
|
||||||
|
environment::Environment,
|
||||||
error::Error,
|
error::Error,
|
||||||
io::{scheduler::ScheduleMethod, source_client::HttpClient},
|
io::{
|
||||||
|
apc::{AsyncProcedureCall, Message},
|
||||||
|
scheduler::Scheduler,
|
||||||
|
source_client::HttpClient,
|
||||||
|
transferables::{DefaultTransferables, Transferables},
|
||||||
|
},
|
||||||
map_schedule::InteractiveMapSchedule,
|
map_schedule::InteractiveMapSchedule,
|
||||||
window::{EventLoop, HeadedMapWindow, MapWindowConfig},
|
window::{EventLoop, HeadedMapWindow, MapWindowConfig},
|
||||||
};
|
};
|
||||||
@ -52,28 +60,48 @@ pub struct WinitMapWindow {
|
|||||||
event_loop: Option<WinitEventLoop>,
|
event_loop: Option<WinitEventLoop>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type WinitWindow = winit::window::Window;
|
|
||||||
pub type WinitEventLoop = winit::event_loop::EventLoop<()>;
|
|
||||||
|
|
||||||
impl WinitMapWindow {
|
impl WinitMapWindow {
|
||||||
pub fn take_event_loop(&mut self) -> Option<WinitEventLoop> {
|
pub fn take_event_loop(&mut self) -> Option<WinitEventLoop> {
|
||||||
self.event_loop.take()
|
self.event_loop.take()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type WinitWindow = winit::window::Window;
|
||||||
|
pub type WinitEventLoop = winit::event_loop::EventLoop<()>;
|
||||||
|
|
||||||
|
pub struct WinitEnvironment<
|
||||||
|
S: Scheduler,
|
||||||
|
HC: HttpClient,
|
||||||
|
T: Transferables,
|
||||||
|
APC: AsyncProcedureCall<T, HC>,
|
||||||
|
> {
|
||||||
|
phantom_s: PhantomData<S>,
|
||||||
|
phantom_hc: PhantomData<HC>,
|
||||||
|
phantom_t: PhantomData<T>,
|
||||||
|
phantom_apc: PhantomData<APC>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: Scheduler, HC: HttpClient, T: Transferables, APC: AsyncProcedureCall<T, HC>> Environment
|
||||||
|
for WinitEnvironment<S, HC, T, APC>
|
||||||
|
{
|
||||||
|
type MapWindowConfig = WinitMapWindowConfig;
|
||||||
|
type AsyncProcedureCall = APC;
|
||||||
|
type Scheduler = S;
|
||||||
|
type HttpClient = HC;
|
||||||
|
type Transferables = T;
|
||||||
|
}
|
||||||
|
|
||||||
///Main (platform-specific) main loop which handles:
|
///Main (platform-specific) main loop which handles:
|
||||||
///* Input (Mouse/Keyboard)
|
///* Input (Mouse/Keyboard)
|
||||||
///* Platform Events like suspend/resume
|
///* Platform Events like suspend/resume
|
||||||
///* Render a new frame
|
///* Render a new frame
|
||||||
impl<MWC, SM, HC> EventLoop<MWC, SM, HC> for WinitMapWindow
|
impl<E: Environment> EventLoop<E> for WinitMapWindow
|
||||||
where
|
where
|
||||||
MWC: MapWindowConfig<MapWindow = WinitMapWindow>,
|
E::MapWindowConfig: MapWindowConfig<MapWindow = WinitMapWindow>,
|
||||||
SM: ScheduleMethod,
|
|
||||||
HC: HttpClient,
|
|
||||||
{
|
{
|
||||||
fn run(
|
fn run(
|
||||||
mut self,
|
mut self,
|
||||||
mut map_schedule: InteractiveMapSchedule<MWC, SM, HC>,
|
map_schedule: Rc<RefCell<InteractiveMapSchedule<E>>>,
|
||||||
max_frames: Option<u64>,
|
max_frames: Option<u64>,
|
||||||
) {
|
) {
|
||||||
let mut last_render_time = Instant::now();
|
let mut last_render_time = Instant::now();
|
||||||
@ -84,6 +112,8 @@ where
|
|||||||
self.take_event_loop()
|
self.take_event_loop()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.run(move |event, _, control_flow| {
|
.run(move |event, _, control_flow| {
|
||||||
|
let mut map_schedule = map_schedule.deref().borrow_mut();
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
if !map_schedule.is_initialized() && event == Event::Resumed {
|
if !map_schedule.is_initialized() && event == Event::Resumed {
|
||||||
use tokio::{runtime::Handle, task};
|
use tokio::{runtime::Handle, task};
|
||||||
|
|||||||
@ -3,10 +3,16 @@
|
|||||||
//! * Platform Events like suspend/resume
|
//! * Platform Events like suspend/resume
|
||||||
//! * Render a new frame
|
//! * Render a new frame
|
||||||
|
|
||||||
use maplibre::window::{HeadedMapWindow, MapWindow, MapWindowConfig, WindowSize};
|
use maplibre::{
|
||||||
|
io::apc::SchedulerAsyncProcedureCall,
|
||||||
|
platform::{http_client::ReqwestHttpClient, run_multithreaded, scheduler::TokioScheduler},
|
||||||
|
window::{HeadedMapWindow, MapWindow, MapWindowConfig, WindowSize},
|
||||||
|
MapBuilder,
|
||||||
|
};
|
||||||
use winit::window::WindowBuilder;
|
use winit::window::WindowBuilder;
|
||||||
|
|
||||||
use super::{WinitEventLoop, WinitMapWindow, WinitMapWindowConfig, WinitWindow};
|
use super::{WinitEventLoop, WinitMapWindow, WinitMapWindowConfig, WinitWindow};
|
||||||
|
use crate::winit::WinitEnvironment;
|
||||||
|
|
||||||
impl MapWindow for WinitMapWindow {
|
impl MapWindow for WinitMapWindow {
|
||||||
fn size(&self) -> WindowSize {
|
fn size(&self) -> WindowSize {
|
||||||
@ -47,3 +53,21 @@ impl MapWindowConfig for WinitMapWindowConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn run_headed_map(cache_path: Option<String>) {
|
||||||
|
run_multithreaded(async {
|
||||||
|
let client = ReqwestHttpClient::new(cache_path);
|
||||||
|
MapBuilder::<WinitEnvironment<_, _, _, SchedulerAsyncProcedureCall<_, _>>>::new()
|
||||||
|
.with_map_window_config(WinitMapWindowConfig::new("maplibre".to_string()))
|
||||||
|
.with_http_client(client.clone())
|
||||||
|
.with_apc(SchedulerAsyncProcedureCall::new(
|
||||||
|
client,
|
||||||
|
TokioScheduler::new(),
|
||||||
|
))
|
||||||
|
.with_scheduler(TokioScheduler::new())
|
||||||
|
.build()
|
||||||
|
.initialize()
|
||||||
|
.await
|
||||||
|
.run()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@ -19,6 +19,7 @@ headless = ["png"]
|
|||||||
|
|
||||||
[target.'cfg(any(target_os = "macos", target_os = "ios", target_os = "linux", target_os = "android", target_os = "windows"))'.dependencies]
|
[target.'cfg(any(target_os = "macos", target_os = "ios", target_os = "linux", target_os = "android", target_os = "windows"))'.dependencies]
|
||||||
tokio = { version = "1.20.1", features = ["macros", "rt", "rt-multi-thread", "sync", "time"] }
|
tokio = { version = "1.20.1", features = ["macros", "rt", "rt-multi-thread", "sync", "time"] }
|
||||||
|
tokio-util = { version = "0.7.1", features = ["rt"] }
|
||||||
env_logger = "0.9.0"
|
env_logger = "0.9.0"
|
||||||
reqwest = { version = "0.11.11", default-features = false, features = ["rustls-tls", "gzip"] }
|
reqwest = { version = "0.11.11", default-features = false, features = ["rustls-tls", "gzip"] }
|
||||||
reqwest-middleware-cache = "0.1.1" # FIXME: Untrusted dependency
|
reqwest-middleware-cache = "0.1.1" # FIXME: Untrusted dependency
|
||||||
@ -32,7 +33,7 @@ reqwest = { version = "0.11.11", default-features = false, features = ["rustls-t
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
async-trait = "0.1.57"
|
async-trait = "0.1.57"
|
||||||
instant = { version = "0.1.12", features = ["wasm-bindgen"] } # FIXME: Untrusted dependency
|
instant = { version = "0.1.12", features = ["wasm-bindgen"] } # TODO: Untrusted dependency
|
||||||
|
|
||||||
# Tracing
|
# Tracing
|
||||||
tracing = "0.1.36"
|
tracing = "0.1.36"
|
||||||
|
|||||||
@ -6,7 +6,9 @@ use std::{
|
|||||||
fmt::{Display, Formatter},
|
fmt::{Display, Formatter},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use bytemuck_derive::{Pod, Zeroable};
|
||||||
use cgmath::{num_traits::Pow, AbsDiffEq, Matrix4, Point3, Vector3};
|
use cgmath::{num_traits::Pow, AbsDiffEq, Matrix4, Point3, Vector3};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
style::source::TileAddressingScheme,
|
style::source::TileAddressingScheme,
|
||||||
@ -67,7 +69,23 @@ impl fmt::Debug for Quadkey {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Ord, PartialOrd, Eq, PartialEq, Hash, Copy, Clone, Debug, Default)]
|
// FIXME: does Pod and Zeroable make sense?
|
||||||
|
#[derive(
|
||||||
|
Ord,
|
||||||
|
PartialOrd,
|
||||||
|
Eq,
|
||||||
|
PartialEq,
|
||||||
|
Hash,
|
||||||
|
Copy,
|
||||||
|
Clone,
|
||||||
|
Debug,
|
||||||
|
Default,
|
||||||
|
Serialize,
|
||||||
|
Deserialize,
|
||||||
|
Pod,
|
||||||
|
Zeroable,
|
||||||
|
)]
|
||||||
|
#[repr(C)]
|
||||||
pub struct ZoomLevel(u8);
|
pub struct ZoomLevel(u8);
|
||||||
|
|
||||||
impl ZoomLevel {
|
impl ZoomLevel {
|
||||||
@ -83,7 +101,7 @@ impl std::ops::Add<u8> for ZoomLevel {
|
|||||||
type Output = ZoomLevel;
|
type Output = ZoomLevel;
|
||||||
|
|
||||||
fn add(self, rhs: u8) -> Self::Output {
|
fn add(self, rhs: u8) -> Self::Output {
|
||||||
let zoom_level = self.0.checked_add(rhs).unwrap();
|
let zoom_level = self.0.checked_add(rhs).expect("zoom level overflowed");
|
||||||
ZoomLevel(zoom_level)
|
ZoomLevel(zoom_level)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -92,7 +110,7 @@ impl std::ops::Sub<u8> for ZoomLevel {
|
|||||||
type Output = ZoomLevel;
|
type Output = ZoomLevel;
|
||||||
|
|
||||||
fn sub(self, rhs: u8) -> Self::Output {
|
fn sub(self, rhs: u8) -> Self::Output {
|
||||||
let zoom_level = self.0.checked_sub(rhs).unwrap();
|
let zoom_level = self.0.checked_sub(rhs).expect("zoom level underflowed");
|
||||||
ZoomLevel(zoom_level)
|
ZoomLevel(zoom_level)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -289,7 +307,22 @@ impl From<(u32, u32, ZoomLevel)> for TileCoords {
|
|||||||
/// # Coordinate System Origin
|
/// # Coordinate System Origin
|
||||||
///
|
///
|
||||||
/// The origin of the coordinate system is in the upper-left corner.
|
/// The origin of the coordinate system is in the upper-left corner.
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
// FIXME: does Zeroable make sense?
|
||||||
|
#[derive(
|
||||||
|
Clone,
|
||||||
|
Copy,
|
||||||
|
Debug,
|
||||||
|
PartialEq,
|
||||||
|
Eq,
|
||||||
|
PartialOrd,
|
||||||
|
Ord,
|
||||||
|
Hash,
|
||||||
|
Default,
|
||||||
|
Serialize,
|
||||||
|
Deserialize,
|
||||||
|
Zeroable,
|
||||||
|
)]
|
||||||
|
#[repr(C)]
|
||||||
pub struct WorldTileCoords {
|
pub struct WorldTileCoords {
|
||||||
pub x: i32,
|
pub x: i32,
|
||||||
pub y: i32,
|
pub y: i32,
|
||||||
|
|||||||
19
maplibre/src/environment.rs
Normal file
19
maplibre/src/environment.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
use crate::{
|
||||||
|
io::{
|
||||||
|
apc::AsyncProcedureCall,
|
||||||
|
transferables::{
|
||||||
|
DefaultTessellatedLayer, DefaultTileTessellated, DefaultUnavailableLayer, Transferables,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
HttpClient, MapWindowConfig, Scheduler,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub trait Environment: 'static {
|
||||||
|
type MapWindowConfig: MapWindowConfig;
|
||||||
|
|
||||||
|
type AsyncProcedureCall: AsyncProcedureCall<Self::Transferables, Self::HttpClient>;
|
||||||
|
type Scheduler: Scheduler;
|
||||||
|
type HttpClient: HttpClient;
|
||||||
|
|
||||||
|
type Transferables: Transferables;
|
||||||
|
}
|
||||||
@ -4,6 +4,7 @@ use std::{
|
|||||||
future::Future,
|
future::Future,
|
||||||
io::Write,
|
io::Write,
|
||||||
iter,
|
iter,
|
||||||
|
marker::PhantomData,
|
||||||
ops::{Deref, Range},
|
ops::{Deref, Range},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
@ -17,11 +18,12 @@ use crate::{
|
|||||||
error::Error,
|
error::Error,
|
||||||
headless::utils::HeadlessPipelineProcessor,
|
headless::utils::HeadlessPipelineProcessor,
|
||||||
io::{
|
io::{
|
||||||
|
apc::{AsyncProcedureCall, SchedulerAsyncProcedureCall},
|
||||||
pipeline::{PipelineContext, Processable},
|
pipeline::{PipelineContext, Processable},
|
||||||
source_client::HttpSourceClient,
|
source_client::HttpSourceClient,
|
||||||
tile_pipelines::build_vector_tile_pipeline,
|
tile_pipelines::build_vector_tile_pipeline,
|
||||||
tile_repository::{StoredLayer, TileRepository},
|
tile_repository::{StoredLayer, TileRepository},
|
||||||
tile_request_state::TileRequestState,
|
transferables::{DefaultTransferables, Transferables},
|
||||||
TileRequest,
|
TileRequest,
|
||||||
},
|
},
|
||||||
render::{
|
render::{
|
||||||
@ -35,7 +37,7 @@ use crate::{
|
|||||||
RenderState,
|
RenderState,
|
||||||
},
|
},
|
||||||
schedule::{Schedule, Stage},
|
schedule::{Schedule, Stage},
|
||||||
HttpClient, MapWindow, MapWindowConfig, Renderer, ScheduleMethod, Scheduler, Style, WindowSize,
|
Environment, HttpClient, MapWindow, MapWindowConfig, Renderer, Scheduler, Style, WindowSize,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct HeadlessMapWindowConfig {
|
pub struct HeadlessMapWindowConfig {
|
||||||
@ -60,56 +62,57 @@ impl MapWindow for HeadlessMapWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct HeadlessMap<MWC, SM, HC>
|
pub struct HeadlessEnvironment<
|
||||||
where
|
S: Scheduler,
|
||||||
MWC: MapWindowConfig,
|
|
||||||
SM: ScheduleMethod,
|
|
||||||
HC: HttpClient,
|
HC: HttpClient,
|
||||||
{
|
T: Transferables,
|
||||||
pub map_schedule: HeadlessMapSchedule<MWC, SM, HC>,
|
APC: AsyncProcedureCall<T, HC>,
|
||||||
pub window: MWC::MapWindow,
|
> {
|
||||||
|
phantom_s: PhantomData<S>,
|
||||||
|
phantom_hc: PhantomData<HC>,
|
||||||
|
phantom_t: PhantomData<T>,
|
||||||
|
phantom_apc: PhantomData<APC>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<MWC, SM, HC> HeadlessMap<MWC, SM, HC>
|
impl<S: Scheduler, HC: HttpClient, T: Transferables, APC: AsyncProcedureCall<T, HC>> Environment
|
||||||
where
|
for HeadlessEnvironment<S, HC, T, APC>
|
||||||
MWC: MapWindowConfig,
|
|
||||||
SM: ScheduleMethod,
|
|
||||||
HC: HttpClient,
|
|
||||||
{
|
{
|
||||||
pub fn map_schedule_mut(&mut self) -> &mut HeadlessMapSchedule<MWC, SM, HC> {
|
type MapWindowConfig = HeadlessMapWindowConfig;
|
||||||
|
type AsyncProcedureCall = APC;
|
||||||
|
type Scheduler = S;
|
||||||
|
type HttpClient = HC;
|
||||||
|
type Transferables = T;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct HeadlessMap<E: Environment> {
|
||||||
|
pub map_schedule: HeadlessMapSchedule<E>,
|
||||||
|
pub window: <E::MapWindowConfig as MapWindowConfig>::MapWindow,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Environment> HeadlessMap<E> {
|
||||||
|
pub fn map_schedule_mut(&mut self) -> &mut HeadlessMapSchedule<E> {
|
||||||
&mut self.map_schedule
|
&mut self.map_schedule
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stores the state of the map, dispatches tile fetching and caching, tessellation and drawing.
|
/// Stores the state of the map, dispatches tile fetching and caching, tessellation and drawing.
|
||||||
pub struct HeadlessMapSchedule<MWC, SM, HC>
|
pub struct HeadlessMapSchedule<E: Environment> {
|
||||||
where
|
map_window_config: E::MapWindowConfig,
|
||||||
MWC: MapWindowConfig,
|
|
||||||
SM: ScheduleMethod,
|
|
||||||
HC: HttpClient,
|
|
||||||
{
|
|
||||||
map_window_config: MWC,
|
|
||||||
|
|
||||||
pub map_context: MapContext,
|
pub map_context: MapContext,
|
||||||
|
|
||||||
schedule: Schedule,
|
schedule: Schedule,
|
||||||
scheduler: Scheduler<SM>,
|
scheduler: E::Scheduler,
|
||||||
http_client: HC,
|
http_client: E::HttpClient,
|
||||||
tile_request_state: TileRequestState,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<MWC, SM, HC> HeadlessMapSchedule<MWC, SM, HC>
|
impl<E: Environment> HeadlessMapSchedule<E> {
|
||||||
where
|
|
||||||
MWC: MapWindowConfig,
|
|
||||||
SM: ScheduleMethod,
|
|
||||||
HC: HttpClient,
|
|
||||||
{
|
|
||||||
pub fn new(
|
pub fn new(
|
||||||
map_window_config: MWC,
|
map_window_config: E::MapWindowConfig,
|
||||||
window_size: WindowSize,
|
window_size: WindowSize,
|
||||||
renderer: Renderer,
|
renderer: Renderer,
|
||||||
scheduler: Scheduler<SM>,
|
scheduler: E::Scheduler,
|
||||||
http_client: HC,
|
http_client: E::HttpClient,
|
||||||
style: Style,
|
style: Style,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let view_state = ViewState::new(
|
let view_state = ViewState::new(
|
||||||
@ -122,12 +125,12 @@ where
|
|||||||
let tile_repository = TileRepository::new();
|
let tile_repository = TileRepository::new();
|
||||||
let mut schedule = Schedule::default();
|
let mut schedule = Schedule::default();
|
||||||
|
|
||||||
let mut graph = create_default_render_graph().unwrap();
|
let mut graph = create_default_render_graph().unwrap(); // TODO: remove unwrap
|
||||||
let draw_graph = graph.get_sub_graph_mut(draw_graph::NAME).unwrap();
|
let draw_graph = graph.get_sub_graph_mut(draw_graph::NAME).unwrap(); // TODO: remove unwrap
|
||||||
draw_graph.add_node(draw_graph::node::COPY, CopySurfaceBufferNode::default());
|
draw_graph.add_node(draw_graph::node::COPY, CopySurfaceBufferNode::default());
|
||||||
draw_graph
|
draw_graph
|
||||||
.add_node_edge(draw_graph::node::MAIN_PASS, draw_graph::node::COPY)
|
.add_node_edge(draw_graph::node::MAIN_PASS, draw_graph::node::COPY)
|
||||||
.unwrap();
|
.unwrap(); // TODO: remove unwrap
|
||||||
|
|
||||||
register_default_render_stages(graph, &mut schedule);
|
register_default_render_stages(graph, &mut schedule);
|
||||||
|
|
||||||
@ -147,7 +150,6 @@ where
|
|||||||
schedule,
|
schedule,
|
||||||
scheduler,
|
scheduler,
|
||||||
http_client,
|
http_client,
|
||||||
tile_request_state: Default::default(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,10 +162,10 @@ where
|
|||||||
pub fn schedule(&self) -> &Schedule {
|
pub fn schedule(&self) -> &Schedule {
|
||||||
&self.schedule
|
&self.schedule
|
||||||
}
|
}
|
||||||
pub fn scheduler(&self) -> &Scheduler<SM> {
|
pub fn scheduler(&self) -> &E::Scheduler {
|
||||||
&self.scheduler
|
&self.scheduler
|
||||||
}
|
}
|
||||||
pub fn http_client(&self) -> &HC {
|
pub fn http_client(&self) -> &E::HttpClient {
|
||||||
&self.http_client
|
&self.http_client
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,13 +178,13 @@ where
|
|||||||
.filter_map(|layer| layer.source_layer.clone())
|
.filter_map(|layer| layer.source_layer.clone())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let http_source_client: HttpSourceClient<HC> =
|
let http_source_client: HttpSourceClient<E::HttpClient> =
|
||||||
HttpSourceClient::new(self.http_client.clone());
|
HttpSourceClient::new(self.http_client.clone());
|
||||||
|
|
||||||
let data = http_source_client
|
let data = http_source_client
|
||||||
.fetch(&coords)
|
.fetch(&coords)
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap() // TODO: remove unwrap
|
||||||
.into_boxed_slice();
|
.into_boxed_slice();
|
||||||
|
|
||||||
let mut pipeline_context = PipelineContext::new(HeadlessPipelineProcessor::default());
|
let mut pipeline_context = PipelineContext::new(HeadlessPipelineProcessor::default());
|
||||||
@ -193,15 +195,11 @@ where
|
|||||||
layers: source_layers,
|
layers: source_layers,
|
||||||
};
|
};
|
||||||
|
|
||||||
let request_id = self
|
pipeline.process((request, data), &mut pipeline_context);
|
||||||
.tile_request_state
|
|
||||||
.start_tile_request(request.clone())?;
|
|
||||||
pipeline.process((request, request_id, data), &mut pipeline_context);
|
|
||||||
self.tile_request_state.finish_tile_request(request_id);
|
|
||||||
|
|
||||||
let mut processor = pipeline_context
|
let mut processor = pipeline_context
|
||||||
.take_processor::<HeadlessPipelineProcessor>()
|
.take_processor::<HeadlessPipelineProcessor>()
|
||||||
.unwrap();
|
.unwrap(); // TODO: remove unwrap
|
||||||
|
|
||||||
if let Eventually::Initialized(pool) = self.map_context.renderer.state.buffer_pool_mut() {
|
if let Eventually::Initialized(pool) = self.map_context.renderer.state.buffer_pool_mut() {
|
||||||
pool.clear();
|
pool.clear();
|
||||||
@ -210,6 +208,9 @@ where
|
|||||||
self.map_context.tile_repository.clear();
|
self.map_context.tile_repository.clear();
|
||||||
|
|
||||||
while let Some(layer) = processor.layers.pop() {
|
while let Some(layer) = processor.layers.pop() {
|
||||||
|
self.map_context
|
||||||
|
.tile_repository
|
||||||
|
.create_tile(&layer.get_coords());
|
||||||
self.map_context
|
self.map_context
|
||||||
.tile_repository
|
.tile_repository
|
||||||
.put_tessellated_layer(layer);
|
.put_tessellated_layer(layer);
|
||||||
@ -261,7 +262,7 @@ impl Node for CopySurfaceBufferNode {
|
|||||||
std::num::NonZeroU32::new(
|
std::num::NonZeroU32::new(
|
||||||
buffered_texture.buffer_dimensions.padded_bytes_per_row as u32,
|
buffered_texture.buffer_dimensions.padded_bytes_per_row as u32,
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(), // TODO: remove unwrap
|
||||||
),
|
),
|
||||||
rows_per_image: None,
|
rows_per_image: None,
|
||||||
},
|
},
|
||||||
@ -340,9 +341,9 @@ pub mod utils {
|
|||||||
) {
|
) {
|
||||||
self.layers.push(StoredLayer::TessellatedLayer {
|
self.layers.push(StoredLayer::TessellatedLayer {
|
||||||
coords: *coords,
|
coords: *coords,
|
||||||
|
layer_name: layer_data.name,
|
||||||
buffer,
|
buffer,
|
||||||
feature_indices,
|
feature_indices,
|
||||||
layer_data,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
121
maplibre/src/io/apc.rs
Normal file
121
maplibre/src/io/apc.rs
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
future::Future,
|
||||||
|
pin::Pin,
|
||||||
|
sync::{
|
||||||
|
mpsc,
|
||||||
|
mpsc::{Receiver, Sender},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
coords::WorldTileCoords,
|
||||||
|
io::{
|
||||||
|
source_client::{HttpSourceClient, SourceClient},
|
||||||
|
transferables::{DefaultTransferables, Transferables},
|
||||||
|
TileRequest,
|
||||||
|
},
|
||||||
|
Environment, HttpClient, Scheduler,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The result of the tessellation of a tile.
|
||||||
|
/// `TessellatedLayer` contains the result of the tessellation for a specific layer, otherwise
|
||||||
|
/// `UnavailableLayer` if the layer doesn't exist.
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum Message<T: Transferables> {
|
||||||
|
TileTessellated(T::TileTessellated),
|
||||||
|
UnavailableLayer(T::UnavailableLayer),
|
||||||
|
TessellatedLayer(T::TessellatedLayer),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
pub enum Input {
|
||||||
|
TileRequest(TileRequest),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Context<T: Transferables, HC: HttpClient>: Send + 'static {
|
||||||
|
fn send(&self, data: Message<T>);
|
||||||
|
|
||||||
|
fn source_client(&self) -> &SourceClient<HC>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no-thread-safe-futures"))]
|
||||||
|
pub type AsyncProcedureFuture = Pin<Box<(dyn Future<Output = ()> + Send + 'static)>>;
|
||||||
|
#[cfg(feature = "no-thread-safe-futures")]
|
||||||
|
pub type AsyncProcedureFuture = Pin<Box<(dyn Future<Output = ()> + 'static)>>;
|
||||||
|
|
||||||
|
pub type AsyncProcedure<C> = fn(input: Input, context: C) -> AsyncProcedureFuture;
|
||||||
|
|
||||||
|
pub trait AsyncProcedureCall<T: Transferables, HC: HttpClient>: 'static {
|
||||||
|
type Context: Context<T, HC> + Send;
|
||||||
|
|
||||||
|
fn receive(&mut self) -> Option<Message<T>>;
|
||||||
|
|
||||||
|
fn schedule(&self, input: Input, procedure: AsyncProcedure<Self::Context>);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SchedulerContext<T: Transferables, HC: HttpClient> {
|
||||||
|
sender: Sender<Message<T>>,
|
||||||
|
source_client: SourceClient<HC>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Transferables, HC: HttpClient> Context<T, HC> for SchedulerContext<T, HC> {
|
||||||
|
fn send(&self, data: Message<T>) {
|
||||||
|
self.sender.send(data).unwrap(); // FIXME (wasm-executor): Remove unwrap
|
||||||
|
}
|
||||||
|
|
||||||
|
fn source_client(&self) -> &SourceClient<HC> {
|
||||||
|
&self.source_client
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SchedulerAsyncProcedureCall<HC: HttpClient, S: Scheduler> {
|
||||||
|
channel: (
|
||||||
|
Sender<Message<DefaultTransferables>>,
|
||||||
|
Receiver<Message<DefaultTransferables>>,
|
||||||
|
),
|
||||||
|
http_client: HC,
|
||||||
|
scheduler: S,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<HC: HttpClient, S: Scheduler> SchedulerAsyncProcedureCall<HC, S> {
|
||||||
|
pub fn new(http_client: HC, scheduler: S) -> Self {
|
||||||
|
Self {
|
||||||
|
channel: mpsc::channel(),
|
||||||
|
http_client,
|
||||||
|
scheduler,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<HC: HttpClient, S: Scheduler> AsyncProcedureCall<DefaultTransferables, HC>
|
||||||
|
for SchedulerAsyncProcedureCall<HC, S>
|
||||||
|
{
|
||||||
|
type Context = SchedulerContext<DefaultTransferables, HC>;
|
||||||
|
|
||||||
|
fn receive(&mut self) -> Option<Message<DefaultTransferables>> {
|
||||||
|
let transferred = self.channel.1.try_recv().ok()?;
|
||||||
|
Some(transferred)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn schedule(&self, input: Input, procedure: AsyncProcedure<Self::Context>) {
|
||||||
|
let sender = self.channel.0.clone();
|
||||||
|
let client = self.http_client.clone(); // FIXME (wasm-executor): do not clone each time
|
||||||
|
|
||||||
|
self.scheduler
|
||||||
|
.schedule(move || async move {
|
||||||
|
(procedure)(
|
||||||
|
input,
|
||||||
|
SchedulerContext {
|
||||||
|
sender,
|
||||||
|
source_client: SourceClient::Http(HttpSourceClient::new(client)),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,8 +2,11 @@
|
|||||||
|
|
||||||
use std::{collections::HashSet, fmt};
|
use std::{collections::HashSet, fmt};
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::coords::WorldTileCoords;
|
use crate::coords::WorldTileCoords;
|
||||||
|
|
||||||
|
pub mod apc;
|
||||||
pub mod geometry_index;
|
pub mod geometry_index;
|
||||||
pub mod pipeline;
|
pub mod pipeline;
|
||||||
pub mod scheduler;
|
pub mod scheduler;
|
||||||
@ -12,12 +15,12 @@ pub mod source_client;
|
|||||||
pub mod static_tile_fetcher;
|
pub mod static_tile_fetcher;
|
||||||
pub mod tile_pipelines;
|
pub mod tile_pipelines;
|
||||||
pub mod tile_repository;
|
pub mod tile_repository;
|
||||||
pub mod tile_request_state;
|
pub mod transferables;
|
||||||
|
|
||||||
pub use geozero::mvt::tile::Layer as RawLayer;
|
pub use geozero::mvt::tile::Layer as RawLayer;
|
||||||
|
|
||||||
/// A request for a tile at the given coordinates and in the given layers.
|
/// A request for a tile at the given coordinates and in the given layers.
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
pub struct TileRequest {
|
pub struct TileRequest {
|
||||||
pub coords: WorldTileCoords,
|
pub coords: WorldTileCoords,
|
||||||
pub layers: HashSet<String>,
|
pub layers: HashSet<String>,
|
||||||
@ -28,6 +31,3 @@ impl fmt::Debug for TileRequest {
|
|||||||
write!(f, "TileRequest({}, {:?})", &self.coords, &self.layers)
|
write!(f, "TileRequest({}, {:?})", &self.coords, &self.layers)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The ID format for a tile request.
|
|
||||||
pub type TileRequestID = u32;
|
|
||||||
|
|||||||
@ -5,14 +5,14 @@ use geozero::mvt::tile;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
coords::WorldTileCoords,
|
coords::WorldTileCoords,
|
||||||
io::{geometry_index::IndexedGeometry, TileRequestID},
|
io::geometry_index::IndexedGeometry,
|
||||||
render::ShaderVertex,
|
render::ShaderVertex,
|
||||||
tessellation::{IndexDataType, OverAlignedVertexBuffer},
|
tessellation::{IndexDataType, OverAlignedVertexBuffer},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Processes events which happen during the pipeline execution
|
/// Processes events which happen during the pipeline execution
|
||||||
pub trait PipelineProcessor: Downcast {
|
pub trait PipelineProcessor: Downcast {
|
||||||
fn tile_finished(&mut self, _request_id: TileRequestID, _coords: &WorldTileCoords) {}
|
fn tile_finished(&mut self, _coords: &WorldTileCoords) {}
|
||||||
fn layer_unavailable(&mut self, _coords: &WorldTileCoords, _layer_name: &str) {}
|
fn layer_unavailable(&mut self, _coords: &WorldTileCoords, _layer_name: &str) {}
|
||||||
fn layer_tesselation_finished(
|
fn layer_tesselation_finished(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -30,8 +30,6 @@ pub trait PipelineProcessor: Downcast {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_downcast!(PipelineProcessor);
|
|
||||||
|
|
||||||
/// Context which is available to each step within a [`DataPipeline`]
|
/// Context which is available to each step within a [`DataPipeline`]
|
||||||
pub struct PipelineContext {
|
pub struct PipelineContext {
|
||||||
processor: Box<dyn PipelineProcessor>,
|
processor: Box<dyn PipelineProcessor>,
|
||||||
|
|||||||
@ -5,28 +5,8 @@ use std::future::Future;
|
|||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
|
|
||||||
/// Async/await scheduler.
|
/// Async/await scheduler.
|
||||||
pub struct Scheduler<SM>
|
|
||||||
where
|
|
||||||
SM: ScheduleMethod,
|
|
||||||
{
|
|
||||||
schedule_method: SM,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<SM> Scheduler<SM>
|
|
||||||
where
|
|
||||||
SM: ScheduleMethod,
|
|
||||||
{
|
|
||||||
pub fn new(schedule_method: SM) -> Self {
|
|
||||||
Self { schedule_method }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn schedule_method(&self) -> &SM {
|
|
||||||
&self.schedule_method
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Can schedule a task from a future factory and a shared state.
|
/// Can schedule a task from a future factory and a shared state.
|
||||||
pub trait ScheduleMethod: 'static {
|
pub trait Scheduler: 'static {
|
||||||
#[cfg(not(feature = "no-thread-safe-futures"))]
|
#[cfg(not(feature = "no-thread-safe-futures"))]
|
||||||
fn schedule<T>(
|
fn schedule<T>(
|
||||||
&self,
|
&self,
|
||||||
@ -43,3 +23,14 @@ pub trait ScheduleMethod: 'static {
|
|||||||
where
|
where
|
||||||
T: Future<Output = ()> + 'static;
|
T: Future<Output = ()> + 'static;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct NopScheduler;
|
||||||
|
|
||||||
|
impl Scheduler for NopScheduler {
|
||||||
|
fn schedule<T>(&self, future_factory: impl FnOnce() -> T + Send + 'static) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
T: Future<Output = ()> + 'static,
|
||||||
|
{
|
||||||
|
Err(Error::Schedule)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -46,7 +46,7 @@ impl StaticTileFetcher {
|
|||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
Error::Network("Failed to load tile from within the binary".to_string())
|
Error::Network("Failed to load tile from within the binary".to_string())
|
||||||
})?;
|
})?;
|
||||||
Ok(Vec::from(tile.contents())) // TODO: Unnecessary copy
|
Ok(Vec::from(tile.contents()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,7 @@ use crate::{
|
|||||||
io::{
|
io::{
|
||||||
geometry_index::IndexProcessor,
|
geometry_index::IndexProcessor,
|
||||||
pipeline::{DataPipeline, PipelineContext, PipelineEnd, Processable},
|
pipeline::{DataPipeline, PipelineContext, PipelineEnd, Processable},
|
||||||
TileRequest, TileRequestID,
|
TileRequest,
|
||||||
},
|
},
|
||||||
tessellation::{zero_tessellator::ZeroTessellator, IndexDataType},
|
tessellation::{zero_tessellator::ZeroTessellator, IndexDataType},
|
||||||
};
|
};
|
||||||
@ -16,17 +16,17 @@ use crate::{
|
|||||||
pub struct ParseTile;
|
pub struct ParseTile;
|
||||||
|
|
||||||
impl Processable for ParseTile {
|
impl Processable for ParseTile {
|
||||||
type Input = (TileRequest, TileRequestID, Box<[u8]>);
|
type Input = (TileRequest, Box<[u8]>);
|
||||||
type Output = (TileRequest, TileRequestID, geozero::mvt::Tile);
|
type Output = (TileRequest, geozero::mvt::Tile);
|
||||||
|
|
||||||
// TODO (perf): Maybe force inline
|
// TODO (perf): Maybe force inline
|
||||||
fn process(
|
fn process(
|
||||||
&self,
|
&self,
|
||||||
(tile_request, request_id, data): Self::Input,
|
(tile_request, data): Self::Input,
|
||||||
_context: &mut PipelineContext,
|
_context: &mut PipelineContext,
|
||||||
) -> Self::Output {
|
) -> Self::Output {
|
||||||
let tile = geozero::mvt::Tile::decode(data.as_ref()).expect("failed to load tile");
|
let tile = geozero::mvt::Tile::decode(data.as_ref()).expect("failed to load tile");
|
||||||
(tile_request, request_id, tile)
|
(tile_request, tile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,13 +34,13 @@ impl Processable for ParseTile {
|
|||||||
pub struct IndexLayer;
|
pub struct IndexLayer;
|
||||||
|
|
||||||
impl Processable for IndexLayer {
|
impl Processable for IndexLayer {
|
||||||
type Input = (TileRequest, TileRequestID, geozero::mvt::Tile);
|
type Input = (TileRequest, geozero::mvt::Tile);
|
||||||
type Output = (TileRequest, TileRequestID, geozero::mvt::Tile);
|
type Output = (TileRequest, geozero::mvt::Tile);
|
||||||
|
|
||||||
// TODO (perf): Maybe force inline
|
// TODO (perf): Maybe force inline
|
||||||
fn process(
|
fn process(
|
||||||
&self,
|
&self,
|
||||||
(tile_request, request_id, tile): Self::Input,
|
(tile_request, tile): Self::Input,
|
||||||
context: &mut PipelineContext,
|
context: &mut PipelineContext,
|
||||||
) -> Self::Output {
|
) -> Self::Output {
|
||||||
let index = IndexProcessor::new();
|
let index = IndexProcessor::new();
|
||||||
@ -48,7 +48,7 @@ impl Processable for IndexLayer {
|
|||||||
context
|
context
|
||||||
.processor_mut()
|
.processor_mut()
|
||||||
.layer_indexing_finished(&tile_request.coords, index.get_geometries());
|
.layer_indexing_finished(&tile_request.coords, index.get_geometries());
|
||||||
(tile_request, request_id, tile)
|
(tile_request, tile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,13 +56,13 @@ impl Processable for IndexLayer {
|
|||||||
pub struct TessellateLayer;
|
pub struct TessellateLayer;
|
||||||
|
|
||||||
impl Processable for TessellateLayer {
|
impl Processable for TessellateLayer {
|
||||||
type Input = (TileRequest, TileRequestID, geozero::mvt::Tile);
|
type Input = (TileRequest, geozero::mvt::Tile);
|
||||||
type Output = (TileRequest, TileRequestID, geozero::mvt::Tile);
|
type Output = (TileRequest, geozero::mvt::Tile);
|
||||||
|
|
||||||
// TODO (perf): Maybe force inline
|
// TODO (perf): Maybe force inline
|
||||||
fn process(
|
fn process(
|
||||||
&self,
|
&self,
|
||||||
(tile_request, request_id, mut tile): Self::Input,
|
(tile_request, mut tile): Self::Input,
|
||||||
context: &mut PipelineContext,
|
context: &mut PipelineContext,
|
||||||
) -> Self::Output {
|
) -> Self::Output {
|
||||||
let coords = &tile_request.coords;
|
let coords = &tile_request.coords;
|
||||||
@ -118,11 +118,9 @@ impl Processable for TessellateLayer {
|
|||||||
|
|
||||||
tracing::info!("tile tessellated at {} finished", &tile_request.coords);
|
tracing::info!("tile tessellated at {} finished", &tile_request.coords);
|
||||||
|
|
||||||
context
|
context.processor_mut().tile_finished(&tile_request.coords);
|
||||||
.processor_mut()
|
|
||||||
.tile_finished(request_id, &tile_request.coords);
|
|
||||||
|
|
||||||
(tile_request, request_id, tile)
|
(tile_request, tile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,7 +157,6 @@ mod tests {
|
|||||||
coords: (0, 0, ZoomLevel::default()).into(),
|
coords: (0, 0, ZoomLevel::default()).into(),
|
||||||
layers: Default::default(),
|
layers: Default::default(),
|
||||||
},
|
},
|
||||||
0,
|
|
||||||
Box::new([0]),
|
Box::new([0]),
|
||||||
),
|
),
|
||||||
&mut context,
|
&mut context,
|
||||||
|
|||||||
@ -18,10 +18,10 @@ pub enum StoredLayer {
|
|||||||
},
|
},
|
||||||
TessellatedLayer {
|
TessellatedLayer {
|
||||||
coords: WorldTileCoords,
|
coords: WorldTileCoords,
|
||||||
|
layer_name: String,
|
||||||
buffer: OverAlignedVertexBuffer<ShaderVertex, IndexDataType>,
|
buffer: OverAlignedVertexBuffer<ShaderVertex, IndexDataType>,
|
||||||
/// Holds for each feature the count of indices.
|
/// Holds for each feature the count of indices.
|
||||||
feature_indices: Vec<u32>,
|
feature_indices: Vec<u32>,
|
||||||
layer_data: tile::Layer,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,20 +36,29 @@ impl StoredLayer {
|
|||||||
pub fn layer_name(&self) -> &str {
|
pub fn layer_name(&self) -> &str {
|
||||||
match self {
|
match self {
|
||||||
StoredLayer::UnavailableLayer { layer_name, .. } => layer_name.as_str(),
|
StoredLayer::UnavailableLayer { layer_name, .. } => layer_name.as_str(),
|
||||||
StoredLayer::TessellatedLayer { layer_data, .. } => &layer_data.name,
|
StoredLayer::TessellatedLayer { layer_name, .. } => layer_name.as_str(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Eq, PartialEq)]
|
||||||
|
pub enum TileStatus {
|
||||||
|
Pending,
|
||||||
|
Failed,
|
||||||
|
Success,
|
||||||
|
}
|
||||||
|
|
||||||
/// Stores multiple [StoredLayers](StoredLayer).
|
/// Stores multiple [StoredLayers](StoredLayer).
|
||||||
pub struct StoredTile {
|
pub struct StoredTile {
|
||||||
layers: Vec<StoredLayer>,
|
layers: Vec<StoredLayer>,
|
||||||
|
status: TileStatus,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StoredTile {
|
impl StoredTile {
|
||||||
pub fn new(first_layer: StoredLayer) -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
layers: vec![first_layer],
|
layers: vec![],
|
||||||
|
status: TileStatus::Pending,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -84,7 +93,7 @@ impl TileRepository {
|
|||||||
{
|
{
|
||||||
match entry {
|
match entry {
|
||||||
btree_map::Entry::Vacant(entry) => {
|
btree_map::Entry::Vacant(entry) => {
|
||||||
entry.insert(StoredTile::new(layer));
|
panic!("Can not add a tessellated layer if no request has been started before.")
|
||||||
}
|
}
|
||||||
btree_map::Entry::Occupied(mut entry) => {
|
btree_map::Entry::Occupied(mut entry) => {
|
||||||
entry.get_mut().layers.push(layer);
|
entry.get_mut().layers.push(layer);
|
||||||
@ -105,6 +114,46 @@ impl TileRepository {
|
|||||||
.map(|results| results.layers.iter())
|
.map(|results| results.layers.iter())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new tile.
|
||||||
|
pub fn create_tile(&mut self, coords: &WorldTileCoords) -> bool {
|
||||||
|
if let Some(entry) = coords.build_quad_key().map(|key| self.tree.entry(key)) {
|
||||||
|
match entry {
|
||||||
|
btree_map::Entry::Vacant(entry) => {
|
||||||
|
entry.insert(StoredTile::new());
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if a layer has been fetched.
|
||||||
|
pub fn needs_fetching(&self, coords: &WorldTileCoords) -> bool {
|
||||||
|
if let Some(_) = coords.build_quad_key().and_then(|key| self.tree.get(&key)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn success(&mut self, coords: &WorldTileCoords) {
|
||||||
|
if let Some(cached_tile) = coords
|
||||||
|
.build_quad_key()
|
||||||
|
.and_then(|key| self.tree.get_mut(&key))
|
||||||
|
{
|
||||||
|
cached_tile.status = TileStatus::Success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if a layer has been fetched.
|
||||||
|
pub fn fail(&mut self, coords: &WorldTileCoords) {
|
||||||
|
if let Some(cached_tile) = coords
|
||||||
|
.build_quad_key()
|
||||||
|
.and_then(|key| self.tree.get_mut(&key))
|
||||||
|
{
|
||||||
|
cached_tile.status = TileStatus::Failed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Removes all the cached tessellate layers that are not contained within the given
|
/// Removes all the cached tessellate layers that are not contained within the given
|
||||||
/// layers hashset.
|
/// layers hashset.
|
||||||
pub fn retain_missing_layer_names(
|
pub fn retain_missing_layer_names(
|
||||||
|
|||||||
@ -1,53 +0,0 @@
|
|||||||
//! Tile request state.
|
|
||||||
|
|
||||||
use std::collections::{HashMap, HashSet};
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
coords::WorldTileCoords,
|
|
||||||
io::{TileRequest, TileRequestID},
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Stores a map of pending requests, coords and the current tile being requested.
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct TileRequestState {
|
|
||||||
current_id: TileRequestID,
|
|
||||||
pending_tile_requests: HashMap<TileRequestID, TileRequest>,
|
|
||||||
pending_coords: HashSet<WorldTileCoords>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TileRequestState {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
current_id: 1,
|
|
||||||
pending_tile_requests: Default::default(),
|
|
||||||
pending_coords: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_tile_request_pending(&self, coords: &WorldTileCoords) -> bool {
|
|
||||||
self.pending_coords.contains(coords)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn start_tile_request(&mut self, tile_request: TileRequest) -> Option<TileRequestID> {
|
|
||||||
if self.is_tile_request_pending(&tile_request.coords) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.pending_coords.insert(tile_request.coords);
|
|
||||||
let id = self.current_id;
|
|
||||||
self.pending_tile_requests.insert(id, tile_request);
|
|
||||||
self.current_id += 1;
|
|
||||||
Some(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn finish_tile_request(&mut self, id: TileRequestID) -> Option<TileRequest> {
|
|
||||||
self.pending_tile_requests.remove(&id).map(|request| {
|
|
||||||
self.pending_coords.remove(&request.coords);
|
|
||||||
request
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_tile_request(&self, id: TileRequestID) -> Option<&TileRequest> {
|
|
||||||
self.pending_tile_requests.get(&id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
110
maplibre/src/io/transferables.rs
Normal file
110
maplibre/src/io/transferables.rs
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
use geozero::mvt::{tile, tile::Layer};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
coords::WorldTileCoords,
|
||||||
|
io::tile_repository::StoredLayer,
|
||||||
|
render::ShaderVertex,
|
||||||
|
tessellation::{IndexDataType, OverAlignedVertexBuffer},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub trait TileTessellated: Send {
|
||||||
|
fn new(coords: WorldTileCoords) -> Self;
|
||||||
|
|
||||||
|
fn coords(&self) -> &WorldTileCoords;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait UnavailableLayer: Send {
|
||||||
|
fn new(coords: WorldTileCoords, layer_name: String) -> Self;
|
||||||
|
|
||||||
|
fn to_stored_layer(self) -> StoredLayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait TessellatedLayer: Send {
|
||||||
|
fn new(
|
||||||
|
coords: WorldTileCoords,
|
||||||
|
buffer: OverAlignedVertexBuffer<ShaderVertex, IndexDataType>,
|
||||||
|
feature_indices: Vec<u32>,
|
||||||
|
layer_data: tile::Layer,
|
||||||
|
) -> Self;
|
||||||
|
fn to_stored_layer(self) -> StoredLayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DefaultTileTessellated {
|
||||||
|
pub coords: WorldTileCoords,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TileTessellated for DefaultTileTessellated {
|
||||||
|
fn new(coords: WorldTileCoords) -> Self {
|
||||||
|
Self { coords }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn coords(&self) -> &WorldTileCoords {
|
||||||
|
&self.coords
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DefaultUnavailableLayer {
|
||||||
|
pub coords: WorldTileCoords,
|
||||||
|
pub layer_name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UnavailableLayer for DefaultUnavailableLayer {
|
||||||
|
fn new(coords: WorldTileCoords, layer_name: String) -> Self {
|
||||||
|
Self { coords, layer_name }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_stored_layer(self) -> StoredLayer {
|
||||||
|
StoredLayer::UnavailableLayer {
|
||||||
|
coords: self.coords,
|
||||||
|
layer_name: self.layer_name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DefaultTessellatedLayer {
|
||||||
|
pub coords: WorldTileCoords,
|
||||||
|
pub buffer: OverAlignedVertexBuffer<ShaderVertex, IndexDataType>,
|
||||||
|
/// Holds for each feature the count of indices.
|
||||||
|
pub feature_indices: Vec<u32>,
|
||||||
|
pub layer_data: Layer, // FIXME (wasm-executor): Introduce a better structure for this
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TessellatedLayer for DefaultTessellatedLayer {
|
||||||
|
fn new(
|
||||||
|
coords: WorldTileCoords,
|
||||||
|
buffer: OverAlignedVertexBuffer<ShaderVertex, IndexDataType>,
|
||||||
|
feature_indices: Vec<u32>,
|
||||||
|
layer_data: Layer,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
coords,
|
||||||
|
buffer,
|
||||||
|
feature_indices,
|
||||||
|
layer_data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_stored_layer(self) -> StoredLayer {
|
||||||
|
StoredLayer::TessellatedLayer {
|
||||||
|
coords: self.coords,
|
||||||
|
layer_name: self.layer_data.name,
|
||||||
|
buffer: self.buffer,
|
||||||
|
feature_indices: self.feature_indices,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Transferables: 'static {
|
||||||
|
type TileTessellated: TileTessellated;
|
||||||
|
type UnavailableLayer: UnavailableLayer;
|
||||||
|
type TessellatedLayer: TessellatedLayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct DefaultTransferables;
|
||||||
|
|
||||||
|
impl Transferables for DefaultTransferables {
|
||||||
|
type TileTessellated = DefaultTileTessellated;
|
||||||
|
type UnavailableLayer = DefaultUnavailableLayer;
|
||||||
|
type TessellatedLayer = DefaultTessellatedLayer;
|
||||||
|
}
|
||||||
@ -16,11 +16,15 @@
|
|||||||
//! maplibre = "0.0.2"
|
//! maplibre = "0.0.2"
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
borrow::{Borrow, BorrowMut},
|
||||||
|
cell::RefCell,
|
||||||
|
rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
io::{
|
environment::Environment,
|
||||||
scheduler::{ScheduleMethod, Scheduler},
|
io::{scheduler::Scheduler, source_client::HttpClient},
|
||||||
source_client::HttpClient,
|
|
||||||
},
|
|
||||||
map_schedule::InteractiveMapSchedule,
|
map_schedule::InteractiveMapSchedule,
|
||||||
render::{
|
render::{
|
||||||
settings::{RendererSettings, WgpuSettings},
|
settings::{RendererSettings, WgpuSettings},
|
||||||
@ -56,29 +60,24 @@ pub mod benchmarking;
|
|||||||
// Internal modules
|
// Internal modules
|
||||||
pub(crate) mod tessellation;
|
pub(crate) mod tessellation;
|
||||||
|
|
||||||
|
pub mod environment;
|
||||||
|
|
||||||
|
pub use geozero::mvt::tile;
|
||||||
|
|
||||||
/// The [`Map`] defines the public interface of the map renderer.
|
/// The [`Map`] defines the public interface of the map renderer.
|
||||||
// DO NOT IMPLEMENT INTERNALS ON THIS STRUCT.
|
// DO NOT IMPLEMENT INTERNALS ON THIS STRUCT.
|
||||||
pub struct Map<MWC, SM, HC>
|
pub struct Map<E: Environment> {
|
||||||
where
|
// FIXME (wasm-executor): Avoid RefCell, change ownership model!
|
||||||
MWC: MapWindowConfig,
|
map_schedule: Rc<RefCell<InteractiveMapSchedule<E>>>,
|
||||||
SM: ScheduleMethod,
|
window: RefCell<Option<<E::MapWindowConfig as MapWindowConfig>::MapWindow>>,
|
||||||
HC: HttpClient,
|
|
||||||
{
|
|
||||||
map_schedule: InteractiveMapSchedule<MWC, SM, HC>,
|
|
||||||
window: MWC::MapWindow,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<MWC, SM, HC> Map<MWC, SM, HC>
|
impl<E: Environment> Map<E>
|
||||||
where
|
where
|
||||||
MWC: MapWindowConfig,
|
<E::MapWindowConfig as MapWindowConfig>::MapWindow: EventLoop<E>,
|
||||||
SM: ScheduleMethod,
|
|
||||||
HC: HttpClient,
|
|
||||||
{
|
{
|
||||||
/// Starts the [`crate::map_schedule::MapState`] Runnable with the configured event loop.
|
/// Starts the [`crate::map_schedule::MapState`] Runnable with the configured event loop.
|
||||||
pub fn run(self)
|
pub fn run(&self) {
|
||||||
where
|
|
||||||
MWC::MapWindow: EventLoop<MWC, SM, HC>,
|
|
||||||
{
|
|
||||||
self.run_with_optionally_max_frames(None);
|
self.run_with_optionally_max_frames(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,10 +86,7 @@ where
|
|||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// * `max_frames` - Maximum number of frames per second.
|
/// * `max_frames` - Maximum number of frames per second.
|
||||||
pub fn run_with_max_frames(self, max_frames: u64)
|
pub fn run_with_max_frames(&self, max_frames: u64) {
|
||||||
where
|
|
||||||
MWC::MapWindow: EventLoop<MWC, SM, HC>,
|
|
||||||
{
|
|
||||||
self.run_with_optionally_max_frames(Some(max_frames));
|
self.run_with_optionally_max_frames(Some(max_frames));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,51 +95,42 @@ where
|
|||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// * `max_frames` - Optional maximum number of frames per second.
|
/// * `max_frames` - Optional maximum number of frames per second.
|
||||||
pub fn run_with_optionally_max_frames(self, max_frames: Option<u64>)
|
pub fn run_with_optionally_max_frames(&self, max_frames: Option<u64>) {
|
||||||
where
|
self.window
|
||||||
MWC::MapWindow: EventLoop<MWC, SM, HC>,
|
.borrow_mut()
|
||||||
{
|
.take()
|
||||||
self.window.run(self.map_schedule, max_frames);
|
.unwrap() // FIXME (wasm-executor): Remove unwrap
|
||||||
|
.run(self.map_schedule.clone(), max_frames);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map_schedule(&self) -> &InteractiveMapSchedule<MWC, SM, HC> {
|
pub fn map_schedule(&self) -> Rc<RefCell<InteractiveMapSchedule<E>>> {
|
||||||
&self.map_schedule
|
self.map_schedule.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map_schedule_mut(&mut self) -> &mut InteractiveMapSchedule<MWC, SM, HC> {
|
/* pub fn map_schedule_mut(&mut self) -> &mut InteractiveMapSchedule<E> {
|
||||||
&mut self.map_schedule
|
&mut self.map_schedule
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stores the map configuration before the map's state has been fully initialized.
|
/// Stores the map configuration before the map's state has been fully initialized.
|
||||||
pub struct UninitializedMap<MWC, SM, HC>
|
pub struct UninitializedMap<E: Environment> {
|
||||||
where
|
scheduler: E::Scheduler,
|
||||||
MWC: MapWindowConfig,
|
apc: E::AsyncProcedureCall,
|
||||||
SM: ScheduleMethod,
|
http_client: E::HttpClient,
|
||||||
HC: HttpClient,
|
|
||||||
{
|
|
||||||
scheduler: Scheduler<SM>,
|
|
||||||
http_client: HC,
|
|
||||||
style: Style,
|
style: Style,
|
||||||
|
|
||||||
wgpu_settings: WgpuSettings,
|
wgpu_settings: WgpuSettings,
|
||||||
renderer_settings: RendererSettings,
|
renderer_settings: RendererSettings,
|
||||||
map_window_config: MWC,
|
map_window_config: E::MapWindowConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<MWC, SM, HC> UninitializedMap<MWC, SM, HC>
|
impl<E: Environment> UninitializedMap<E>
|
||||||
where
|
where
|
||||||
MWC: MapWindowConfig,
|
<E::MapWindowConfig as MapWindowConfig>::MapWindow: HeadedMapWindow,
|
||||||
SM: ScheduleMethod,
|
|
||||||
HC: HttpClient,
|
|
||||||
{
|
{
|
||||||
/// Initializes the whole rendering pipeline for the given configuration.
|
/// Initializes the whole rendering pipeline for the given configuration.
|
||||||
/// Returns the initialized map, ready to be run.
|
/// Returns the initialized map, ready to be run.
|
||||||
pub async fn initialize(self) -> Map<MWC, SM, HC>
|
pub async fn initialize(self) -> Map<E> {
|
||||||
where
|
|
||||||
MWC: MapWindowConfig,
|
|
||||||
<MWC as MapWindowConfig>::MapWindow: HeadedMapWindow,
|
|
||||||
{
|
|
||||||
let window = self.map_window_config.create();
|
let window = self.map_window_config.create();
|
||||||
let window_size = window.size();
|
let window_size = window.size();
|
||||||
|
|
||||||
@ -158,22 +145,25 @@ where
|
|||||||
.await
|
.await
|
||||||
.ok();
|
.ok();
|
||||||
Map {
|
Map {
|
||||||
map_schedule: InteractiveMapSchedule::new(
|
map_schedule: Rc::new(RefCell::new(InteractiveMapSchedule::new(
|
||||||
self.map_window_config,
|
self.map_window_config,
|
||||||
window_size,
|
window_size,
|
||||||
renderer,
|
renderer,
|
||||||
self.scheduler,
|
self.scheduler,
|
||||||
|
self.apc,
|
||||||
self.http_client,
|
self.http_client,
|
||||||
self.style,
|
self.style,
|
||||||
self.wgpu_settings,
|
self.wgpu_settings,
|
||||||
self.renderer_settings,
|
self.renderer_settings,
|
||||||
),
|
))),
|
||||||
window,
|
window: RefCell::new(Some(window)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "headless")]
|
#[cfg(feature = "headless")]
|
||||||
pub async fn initialize_headless(self) -> headless::HeadlessMap<MWC, SM, HC> {
|
impl<E: Environment> UninitializedMap<E> {
|
||||||
|
pub async fn initialize_headless(self) -> headless::HeadlessMap<E> {
|
||||||
let window = self.map_window_config.create();
|
let window = self.map_window_config.create();
|
||||||
let window_size = window.size();
|
let window_size = window.size();
|
||||||
|
|
||||||
@ -198,30 +188,22 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MapBuilder<MWC, SM, HC>
|
pub struct MapBuilder<E: Environment> {
|
||||||
where
|
scheduler: Option<E::Scheduler>,
|
||||||
SM: ScheduleMethod,
|
apc: Option<E::AsyncProcedureCall>,
|
||||||
{
|
http_client: Option<E::HttpClient>,
|
||||||
schedule_method: Option<SM>,
|
|
||||||
scheduler: Option<Scheduler<SM>>,
|
|
||||||
http_client: Option<HC>,
|
|
||||||
style: Option<Style>,
|
style: Option<Style>,
|
||||||
|
|
||||||
map_window_config: Option<MWC>,
|
map_window_config: Option<E::MapWindowConfig>,
|
||||||
wgpu_settings: Option<WgpuSettings>,
|
wgpu_settings: Option<WgpuSettings>,
|
||||||
renderer_settings: Option<RendererSettings>,
|
renderer_settings: Option<RendererSettings>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<MWC, SM, HC> MapBuilder<MWC, SM, HC>
|
impl<E: Environment> MapBuilder<E> {
|
||||||
where
|
|
||||||
MWC: MapWindowConfig,
|
|
||||||
SM: ScheduleMethod,
|
|
||||||
HC: HttpClient,
|
|
||||||
{
|
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
schedule_method: None,
|
|
||||||
scheduler: None,
|
scheduler: None,
|
||||||
|
apc: None,
|
||||||
http_client: None,
|
http_client: None,
|
||||||
style: None,
|
style: None,
|
||||||
map_window_config: None,
|
map_window_config: None,
|
||||||
@ -230,7 +212,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_map_window_config(mut self, map_window_config: MWC) -> Self {
|
pub fn with_map_window_config(mut self, map_window_config: E::MapWindowConfig) -> Self {
|
||||||
self.map_window_config = Some(map_window_config);
|
self.map_window_config = Some(map_window_config);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -245,40 +227,36 @@ where
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_schedule_method(mut self, schedule_method: SM) -> Self {
|
pub fn with_scheduler(mut self, scheduler: E::Scheduler) -> Self {
|
||||||
self.schedule_method = Some(schedule_method);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_http_client(mut self, http_client: HC) -> Self {
|
|
||||||
self.http_client = Some(http_client);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_existing_scheduler(mut self, scheduler: Scheduler<SM>) -> Self {
|
|
||||||
self.scheduler = Some(scheduler);
|
self.scheduler = Some(scheduler);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_apc(mut self, apc: E::AsyncProcedureCall) -> Self {
|
||||||
|
self.apc = Some(apc);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_http_client(mut self, http_client: E::HttpClient) -> Self {
|
||||||
|
self.http_client = Some(http_client);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn with_style(mut self, style: Style) -> Self {
|
pub fn with_style(mut self, style: Style) -> Self {
|
||||||
self.style = Some(style);
|
self.style = Some(style);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds the UninitializedMap with the given configuration.
|
/// Builds the UninitializedMap with the given configuration.
|
||||||
pub fn build(self) -> UninitializedMap<MWC, SM, HC> {
|
pub fn build(self) -> UninitializedMap<E> {
|
||||||
let scheduler = self
|
|
||||||
.scheduler
|
|
||||||
.unwrap_or_else(|| Scheduler::new(self.schedule_method.unwrap()));
|
|
||||||
let style = self.style.unwrap_or_default();
|
|
||||||
|
|
||||||
UninitializedMap {
|
UninitializedMap {
|
||||||
scheduler,
|
scheduler: self.scheduler.unwrap(), // TODO: Remove unwrap
|
||||||
http_client: self.http_client.unwrap(),
|
apc: self.apc.unwrap(), // TODO: Remove unwrap
|
||||||
style,
|
http_client: self.http_client.unwrap(), // TODO: Remove unwrap
|
||||||
|
style: self.style.unwrap_or_default(),
|
||||||
wgpu_settings: self.wgpu_settings.unwrap_or_default(),
|
wgpu_settings: self.wgpu_settings.unwrap_or_default(),
|
||||||
renderer_settings: self.renderer_settings.unwrap_or_default(),
|
renderer_settings: self.renderer_settings.unwrap_or_default(),
|
||||||
map_window_config: self.map_window_config.unwrap(),
|
map_window_config: self.map_window_config.unwrap(), // TODO: Remove unwrap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use std::{marker::PhantomData, mem};
|
use std::{cell::RefCell, marker::PhantomData, mem, rc::Rc};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
context::{MapContext, ViewState},
|
context::{MapContext, ViewState},
|
||||||
@ -13,41 +13,32 @@ use crate::{
|
|||||||
schedule::{Schedule, Stage},
|
schedule::{Schedule, Stage},
|
||||||
stages::register_stages,
|
stages::register_stages,
|
||||||
style::Style,
|
style::Style,
|
||||||
HeadedMapWindow, MapWindowConfig, Renderer, RendererSettings, ScheduleMethod, WgpuSettings,
|
Environment, HeadedMapWindow, MapWindowConfig, Renderer, RendererSettings, WgpuSettings,
|
||||||
WindowSize,
|
WindowSize,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Stores the state of the map, dispatches tile fetching and caching, tessellation and drawing.
|
/// Stores the state of the map, dispatches tile fetching and caching, tessellation and drawing.
|
||||||
pub struct InteractiveMapSchedule<MWC, SM, HC>
|
pub struct InteractiveMapSchedule<E: Environment> {
|
||||||
where
|
map_window_config: E::MapWindowConfig,
|
||||||
MWC: MapWindowConfig,
|
|
||||||
SM: ScheduleMethod,
|
// FIXME (wasm-executor): avoid RefCell, change ownership model
|
||||||
HC: HttpClient,
|
pub apc: Rc<RefCell<E::AsyncProcedureCall>>,
|
||||||
{
|
|
||||||
map_window_config: MWC,
|
|
||||||
|
|
||||||
map_context: EventuallyMapContext,
|
map_context: EventuallyMapContext,
|
||||||
|
|
||||||
schedule: Schedule,
|
schedule: Schedule,
|
||||||
|
|
||||||
phantom_sm: PhantomData<SM>,
|
|
||||||
phantom_hc: PhantomData<HC>,
|
|
||||||
|
|
||||||
suspended: bool,
|
suspended: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<MWC, SM, HC> InteractiveMapSchedule<MWC, SM, HC>
|
impl<E: Environment> InteractiveMapSchedule<E> {
|
||||||
where
|
|
||||||
MWC: MapWindowConfig,
|
|
||||||
SM: ScheduleMethod,
|
|
||||||
HC: HttpClient,
|
|
||||||
{
|
|
||||||
pub fn new(
|
pub fn new(
|
||||||
map_window_config: MWC,
|
map_window_config: E::MapWindowConfig,
|
||||||
window_size: WindowSize,
|
window_size: WindowSize,
|
||||||
renderer: Option<Renderer>,
|
renderer: Option<Renderer>,
|
||||||
scheduler: Scheduler<SM>,
|
scheduler: E::Scheduler, // TODO: unused
|
||||||
http_client: HC,
|
apc: E::AsyncProcedureCall,
|
||||||
|
http_client: E::HttpClient,
|
||||||
style: Style,
|
style: Style,
|
||||||
wgpu_settings: WgpuSettings,
|
wgpu_settings: WgpuSettings,
|
||||||
renderer_settings: RendererSettings,
|
renderer_settings: RendererSettings,
|
||||||
@ -63,13 +54,17 @@ where
|
|||||||
let tile_repository = TileRepository::new();
|
let tile_repository = TileRepository::new();
|
||||||
let mut schedule = Schedule::default();
|
let mut schedule = Schedule::default();
|
||||||
|
|
||||||
let http_source_client: HttpSourceClient<HC> = HttpSourceClient::new(http_client);
|
let apc = Rc::new(RefCell::new(apc));
|
||||||
register_stages(&mut schedule, http_source_client, Box::new(scheduler));
|
|
||||||
|
|
||||||
let graph = create_default_render_graph().unwrap();
|
let http_source_client: HttpSourceClient<E::HttpClient> =
|
||||||
|
HttpSourceClient::new(http_client);
|
||||||
|
register_stages::<E>(&mut schedule, http_source_client, apc.clone());
|
||||||
|
|
||||||
|
let graph = create_default_render_graph().unwrap(); // TODO: Remove unwrap
|
||||||
register_default_render_stages(graph, &mut schedule);
|
register_default_render_stages(graph, &mut schedule);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
apc,
|
||||||
map_window_config,
|
map_window_config,
|
||||||
map_context: match renderer {
|
map_context: match renderer {
|
||||||
None => EventuallyMapContext::Premature(PrematureMapContext {
|
None => EventuallyMapContext::Premature(PrematureMapContext {
|
||||||
@ -87,8 +82,6 @@ where
|
|||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
schedule,
|
schedule,
|
||||||
phantom_sm: Default::default(),
|
|
||||||
phantom_hc: Default::default(),
|
|
||||||
suspended: false,
|
suspended: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -116,23 +109,6 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn suspend(&mut self) {
|
|
||||||
self.suspended = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn resume(&mut self, window: &MWC::MapWindow)
|
|
||||||
where
|
|
||||||
<MWC as MapWindowConfig>::MapWindow: HeadedMapWindow,
|
|
||||||
{
|
|
||||||
if let EventuallyMapContext::Full(map_context) = &mut self.map_context {
|
|
||||||
let renderer = &mut map_context.renderer;
|
|
||||||
renderer
|
|
||||||
.state
|
|
||||||
.recreate_surface::<MWC::MapWindow>(window, &renderer.instance);
|
|
||||||
self.suspended = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_initialized(&self) -> bool {
|
pub fn is_initialized(&self) -> bool {
|
||||||
match &self.map_context {
|
match &self.map_context {
|
||||||
EventuallyMapContext::Full(_) => true,
|
EventuallyMapContext::Full(_) => true,
|
||||||
@ -140,10 +116,36 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn late_init(&mut self) -> bool
|
pub fn view_state_mut(&mut self) -> &mut ViewState {
|
||||||
where
|
match &mut self.map_context {
|
||||||
<MWC as MapWindowConfig>::MapWindow: HeadedMapWindow,
|
EventuallyMapContext::Full(MapContext { view_state, .. }) => view_state,
|
||||||
{
|
EventuallyMapContext::Premature(PrematureMapContext { view_state, .. }) => view_state,
|
||||||
|
_ => panic!("should not happen"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn apc(&self) -> &Rc<RefCell<E::AsyncProcedureCall>> {
|
||||||
|
&self.apc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Environment> InteractiveMapSchedule<E>
|
||||||
|
where
|
||||||
|
<E::MapWindowConfig as MapWindowConfig>::MapWindow: HeadedMapWindow,
|
||||||
|
{
|
||||||
|
pub fn suspend(&mut self) {
|
||||||
|
self.suspended = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resume(&mut self, window: &<E::MapWindowConfig as MapWindowConfig>::MapWindow) {
|
||||||
|
if let EventuallyMapContext::Full(map_context) = &mut self.map_context {
|
||||||
|
let renderer = &mut map_context.renderer;
|
||||||
|
renderer.state.recreate_surface(window, &renderer.instance);
|
||||||
|
self.suspended = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn late_init(&mut self) -> bool {
|
||||||
match &self.map_context {
|
match &self.map_context {
|
||||||
EventuallyMapContext::Full(_) => false,
|
EventuallyMapContext::Full(_) => false,
|
||||||
EventuallyMapContext::Premature(PrematureMapContext {
|
EventuallyMapContext::Premature(PrematureMapContext {
|
||||||
@ -155,21 +157,13 @@ where
|
|||||||
let renderer =
|
let renderer =
|
||||||
Renderer::initialize(&window, wgpu_settings.clone(), renderer_settings.clone())
|
Renderer::initialize(&window, wgpu_settings.clone(), renderer_settings.clone())
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap(); // TODO: Remove unwrap
|
||||||
self.map_context.make_full(renderer);
|
self.map_context.make_full(renderer);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
EventuallyMapContext::_Uninitialized => false,
|
EventuallyMapContext::_Uninitialized => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn view_state_mut(&mut self) -> &mut ViewState {
|
|
||||||
match &mut self.map_context {
|
|
||||||
EventuallyMapContext::Full(MapContext { view_state, .. }) => view_state,
|
|
||||||
EventuallyMapContext::Premature(PrematureMapContext { view_state, .. }) => view_state,
|
|
||||||
_ => panic!("should not happen"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PrematureMapContext {
|
pub struct PrematureMapContext {
|
||||||
|
|||||||
@ -36,9 +36,14 @@ pub mod http_client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Scheduler for non-web targets.
|
/// Scheduler for non-web targets.
|
||||||
pub mod schedule_method {
|
pub mod scheduler {
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub use super::noweb::schedule_method::*;
|
pub use super::noweb::scheduler::*;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod trace {
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
pub use super::noweb::trace::*;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
|||||||
@ -3,7 +3,8 @@
|
|||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
|
||||||
pub mod http_client;
|
pub mod http_client;
|
||||||
pub mod schedule_method;
|
pub mod scheduler;
|
||||||
|
pub mod trace;
|
||||||
|
|
||||||
pub fn run_multithreaded<F: Future>(future: F) -> F::Output {
|
pub fn run_multithreaded<F: Future>(future: F) -> F::Output {
|
||||||
tokio::runtime::Builder::new_multi_thread()
|
tokio::runtime::Builder::new_multi_thread()
|
||||||
|
|||||||
@ -1,17 +1,17 @@
|
|||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
|
||||||
use crate::{error::Error, ScheduleMethod};
|
use crate::{error::Error, Scheduler};
|
||||||
|
|
||||||
/// Multi-threading with Tokio.
|
/// Multi-threading with Tokio.
|
||||||
pub struct TokioScheduleMethod;
|
pub struct TokioScheduler;
|
||||||
|
|
||||||
impl TokioScheduleMethod {
|
impl TokioScheduler {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {}
|
Self {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScheduleMethod for TokioScheduleMethod {
|
impl Scheduler for TokioScheduler {
|
||||||
fn schedule<T>(&self, future_factory: impl FnOnce() -> T + Send + 'static) -> Result<(), Error>
|
fn schedule<T>(&self, future_factory: impl FnOnce() -> T + Send + 'static) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
T: Future<Output = ()> + Send + 'static,
|
T: Future<Output = ()> + Send + 'static,
|
||||||
8
maplibre/src/platform/noweb/trace.rs
Normal file
8
maplibre/src/platform/noweb/trace.rs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#[cfg(feature = "trace")]
|
||||||
|
pub fn enable_tracing() {
|
||||||
|
use tracing_subscriber::{layer::SubscriberExt, Registry};
|
||||||
|
|
||||||
|
let subscriber = Registry::default().with(tracing_tracy::TracyLayer::new());
|
||||||
|
|
||||||
|
tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed");
|
||||||
|
}
|
||||||
@ -191,7 +191,7 @@ impl<Q: Queue<B>, B, V: Pod, I: Pod, TM: Pod, FM: Pod> BufferPool<Q, B, V, I, TM
|
|||||||
self.index.get_layers(coords).map(|layers| {
|
self.index.get_layers(coords).map(|layers| {
|
||||||
layers
|
layers
|
||||||
.iter()
|
.iter()
|
||||||
.map(|entry| entry.style_layer.source_layer.as_ref().unwrap().as_str())
|
.map(|entry| entry.style_layer.source_layer.as_ref().unwrap().as_str()) // TODO: Remove unwrap
|
||||||
.collect()
|
.collect()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -84,7 +84,7 @@ impl BufferedTextureHead {
|
|||||||
let padded_buffer = buffer_slice.get_mapped_range();
|
let padded_buffer = buffer_slice.get_mapped_range();
|
||||||
|
|
||||||
let mut png_encoder = png::Encoder::new(
|
let mut png_encoder = png::Encoder::new(
|
||||||
File::create(png_output_path).unwrap(),
|
File::create(png_output_path).unwrap(), // TODO: Remove unwrap
|
||||||
self.buffer_dimensions.width as u32,
|
self.buffer_dimensions.width as u32,
|
||||||
self.buffer_dimensions.height as u32,
|
self.buffer_dimensions.height as u32,
|
||||||
);
|
);
|
||||||
@ -92,17 +92,17 @@ impl BufferedTextureHead {
|
|||||||
png_encoder.set_color(png::ColorType::Rgba);
|
png_encoder.set_color(png::ColorType::Rgba);
|
||||||
let mut png_writer = png_encoder
|
let mut png_writer = png_encoder
|
||||||
.write_header()
|
.write_header()
|
||||||
.unwrap()
|
.unwrap() // TODO: Remove unwrap
|
||||||
.into_stream_writer_with_size(self.buffer_dimensions.unpadded_bytes_per_row)
|
.into_stream_writer_with_size(self.buffer_dimensions.unpadded_bytes_per_row)
|
||||||
.unwrap();
|
.unwrap(); // TODO: Remove unwrap
|
||||||
|
|
||||||
// from the padded_buffer we write just the unpadded bytes into the image
|
// from the padded_buffer we write just the unpadded bytes into the image
|
||||||
for chunk in padded_buffer.chunks(self.buffer_dimensions.padded_bytes_per_row) {
|
for chunk in padded_buffer.chunks(self.buffer_dimensions.padded_bytes_per_row) {
|
||||||
png_writer
|
png_writer
|
||||||
.write_all(&chunk[..self.buffer_dimensions.unpadded_bytes_per_row])
|
.write_all(&chunk[..self.buffer_dimensions.unpadded_bytes_per_row])
|
||||||
.unwrap();
|
.unwrap(); // TODO: Remove unwrap
|
||||||
}
|
}
|
||||||
png_writer.finish().unwrap();
|
png_writer.finish().unwrap(); // TODO: Remove unwrap
|
||||||
|
|
||||||
// With the current interface, we have to make sure all mapped views are
|
// With the current interface, we have to make sure all mapped views are
|
||||||
// dropped before we unmap the buffer.
|
// dropped before we unmap the buffer.
|
||||||
|
|||||||
@ -44,7 +44,7 @@ impl Stage for UploadStage {
|
|||||||
.position
|
.position
|
||||||
.to_homogeneous()
|
.to_homogeneous()
|
||||||
.cast::<f32>()
|
.cast::<f32>()
|
||||||
.unwrap()
|
.unwrap() // TODO: Remove unwrap
|
||||||
.into(),
|
.into(),
|
||||||
))]),
|
))]),
|
||||||
);
|
);
|
||||||
@ -168,7 +168,7 @@ impl UploadStage {
|
|||||||
})
|
})
|
||||||
{
|
{
|
||||||
for style_layer in &style.layers {
|
for style_layer in &style.layers {
|
||||||
let source_layer = style_layer.source_layer.as_ref().unwrap();
|
let source_layer = style_layer.source_layer.as_ref().unwrap(); // TODO: Remove unwrap
|
||||||
|
|
||||||
if let Some(message) = available_layers
|
if let Some(message) = available_layers
|
||||||
.iter()
|
.iter()
|
||||||
@ -187,7 +187,6 @@ impl UploadStage {
|
|||||||
StoredLayer::TessellatedLayer {
|
StoredLayer::TessellatedLayer {
|
||||||
coords,
|
coords,
|
||||||
feature_indices,
|
feature_indices,
|
||||||
layer_data,
|
|
||||||
buffer,
|
buffer,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
@ -197,17 +196,16 @@ impl UploadStage {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let guard = allocate_feature_metadata.enter();
|
let guard = allocate_feature_metadata.enter();
|
||||||
let feature_metadata = layer_data
|
let feature_metadata =
|
||||||
.features
|
(0..feature_indices.len()) // FIXME: Iterate over actual featrues
|
||||||
.iter()
|
.enumerate()
|
||||||
.enumerate()
|
.flat_map(|(i, _feature)| {
|
||||||
.flat_map(|(i, _feature)| {
|
iter::repeat(ShaderFeatureStyle {
|
||||||
iter::repeat(ShaderFeatureStyle {
|
color: color.unwrap(),
|
||||||
color: color.unwrap(),
|
})
|
||||||
|
.take(feature_indices[i] as usize)
|
||||||
})
|
})
|
||||||
.take(feature_indices[i] as usize)
|
.collect::<Vec<_>>();
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
drop(guard);
|
drop(guard);
|
||||||
|
|
||||||
tracing::trace!("Allocating geometry at {}", &coords);
|
tracing::trace!("Allocating geometry at {}", &coords);
|
||||||
|
|||||||
@ -166,8 +166,8 @@ impl<Q: Queue<B>, B> TileViewPattern<Q, B> {
|
|||||||
|
|
||||||
let raw_buffer = bytemuck::cast_slice(buffer.as_slice());
|
let raw_buffer = bytemuck::cast_slice(buffer.as_slice());
|
||||||
if raw_buffer.len() as wgpu::BufferAddress > self.buffer.inner_size {
|
if raw_buffer.len() as wgpu::BufferAddress > self.buffer.inner_size {
|
||||||
/* FIXME: We need to avoid this case by either choosing a proper size
|
/* TODO: We need to avoid this case by either choosing a proper size
|
||||||
(DEFAULT_TILE_VIEW_SIZE), or resizing the buffer */
|
TODO: (DEFAULT_TILE_VIEW_SIZE), or resizing the buffer */
|
||||||
panic!("Buffer is too small to store the tile pattern!");
|
panic!("Buffer is too small to store the tile pattern!");
|
||||||
}
|
}
|
||||||
queue.write_buffer(&self.buffer.inner, 0, raw_buffer);
|
queue.write_buffer(&self.buffer.inner, 0, raw_buffer);
|
||||||
|
|||||||
@ -250,7 +250,7 @@ impl Schedule {
|
|||||||
for label in &self.stage_order {
|
for label in &self.stage_order {
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
let _stage_span = tracing::info_span!("stage", name = ?label).entered();
|
let _stage_span = tracing::info_span!("stage", name = ?label).entered();
|
||||||
let stage = self.stages.get_mut(label).unwrap();
|
let stage = self.stages.get_mut(label).unwrap(); // TODO: Remove unwrap
|
||||||
stage.run(context);
|
stage.run(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,75 +0,0 @@
|
|||||||
use std::{fmt, sync::mpsc};
|
|
||||||
|
|
||||||
use geozero::mvt::tile;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
coords::WorldTileCoords,
|
|
||||||
io::{tile_repository::StoredLayer, TileRequestID},
|
|
||||||
render::ShaderVertex,
|
|
||||||
tessellation::{IndexDataType, OverAlignedVertexBuffer},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub type MessageSender = mpsc::Sender<TessellateMessage>;
|
|
||||||
pub type MessageReceiver = mpsc::Receiver<TessellateMessage>;
|
|
||||||
|
|
||||||
/// [crate::io::TileTessellateMessage] or [crate::io::LayerTessellateMessage] tessellation message.
|
|
||||||
pub enum TessellateMessage {
|
|
||||||
Tile(TileTessellateMessage),
|
|
||||||
Layer(LayerTessellateMessage),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The result of the tessellation of a tile.
|
|
||||||
pub struct TileTessellateMessage {
|
|
||||||
pub request_id: TileRequestID,
|
|
||||||
pub coords: WorldTileCoords,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `TessellatedLayer` contains the result of the tessellation for a specific layer, otherwise
|
|
||||||
/// `UnavailableLayer` if the layer doesn't exist.
|
|
||||||
pub enum LayerTessellateMessage {
|
|
||||||
UnavailableLayer {
|
|
||||||
coords: WorldTileCoords,
|
|
||||||
layer_name: String,
|
|
||||||
},
|
|
||||||
TessellatedLayer {
|
|
||||||
coords: WorldTileCoords,
|
|
||||||
buffer: OverAlignedVertexBuffer<ShaderVertex, IndexDataType>,
|
|
||||||
/// Holds for each feature the count of indices.
|
|
||||||
feature_indices: Vec<u32>,
|
|
||||||
layer_data: tile::Layer,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<StoredLayer> for LayerTessellateMessage {
|
|
||||||
fn into(self) -> StoredLayer {
|
|
||||||
match self {
|
|
||||||
LayerTessellateMessage::UnavailableLayer { coords, layer_name } => {
|
|
||||||
StoredLayer::UnavailableLayer { coords, layer_name }
|
|
||||||
}
|
|
||||||
LayerTessellateMessage::TessellatedLayer {
|
|
||||||
coords,
|
|
||||||
buffer,
|
|
||||||
feature_indices,
|
|
||||||
layer_data,
|
|
||||||
} => StoredLayer::TessellatedLayer {
|
|
||||||
coords,
|
|
||||||
buffer,
|
|
||||||
feature_indices,
|
|
||||||
layer_data,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for LayerTessellateMessage {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"LayerTessellateMessage{}",
|
|
||||||
match self {
|
|
||||||
LayerTessellateMessage::UnavailableLayer { coords, .. } => coords,
|
|
||||||
LayerTessellateMessage::TessellatedLayer { coords, .. } => coords,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,6 +1,11 @@
|
|||||||
//! [Stages](Stage) for requesting and preparing data
|
//! [Stages](Stage) for requesting and preparing data
|
||||||
|
|
||||||
use std::sync::{mpsc, Arc, Mutex};
|
use std::{
|
||||||
|
cell::RefCell,
|
||||||
|
marker::PhantomData,
|
||||||
|
rc::Rc,
|
||||||
|
sync::{mpsc, Arc, Mutex},
|
||||||
|
};
|
||||||
|
|
||||||
use geozero::{mvt::tile, GeozeroDatasource};
|
use geozero::{mvt::tile, GeozeroDatasource};
|
||||||
use request_stage::RequestStage;
|
use request_stage::RequestStage;
|
||||||
@ -9,78 +14,61 @@ use crate::{
|
|||||||
coords::{WorldCoords, WorldTileCoords, Zoom, ZoomLevel},
|
coords::{WorldCoords, WorldTileCoords, Zoom, ZoomLevel},
|
||||||
error::Error,
|
error::Error,
|
||||||
io::{
|
io::{
|
||||||
|
apc::{AsyncProcedureCall, Context, Message},
|
||||||
geometry_index::{GeometryIndex, IndexedGeometry, TileIndex},
|
geometry_index::{GeometryIndex, IndexedGeometry, TileIndex},
|
||||||
pipeline::{PipelineContext, PipelineProcessor, Processable},
|
pipeline::{PipelineContext, PipelineProcessor, Processable},
|
||||||
source_client::HttpSourceClient,
|
source_client::HttpSourceClient,
|
||||||
tile_pipelines::build_vector_tile_pipeline,
|
tile_pipelines::build_vector_tile_pipeline,
|
||||||
tile_request_state::TileRequestState,
|
transferables::{
|
||||||
TileRequest, TileRequestID,
|
DefaultTessellatedLayer, DefaultTileTessellated, DefaultTransferables,
|
||||||
|
DefaultUnavailableLayer, TessellatedLayer, TileTessellated, Transferables,
|
||||||
|
UnavailableLayer,
|
||||||
|
},
|
||||||
|
TileRequest,
|
||||||
},
|
},
|
||||||
render::ShaderVertex,
|
render::ShaderVertex,
|
||||||
schedule::Schedule,
|
schedule::Schedule,
|
||||||
stages::{
|
stages::populate_tile_store_stage::PopulateTileStore,
|
||||||
message::{
|
|
||||||
LayerTessellateMessage, MessageReceiver, MessageSender, TessellateMessage,
|
|
||||||
TileTessellateMessage,
|
|
||||||
},
|
|
||||||
populate_tile_store_stage::PopulateTileStore,
|
|
||||||
},
|
|
||||||
tessellation::{IndexDataType, OverAlignedVertexBuffer},
|
tessellation::{IndexDataType, OverAlignedVertexBuffer},
|
||||||
HttpClient, ScheduleMethod, Scheduler,
|
Environment, HttpClient, Scheduler,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod message;
|
|
||||||
mod populate_tile_store_stage;
|
mod populate_tile_store_stage;
|
||||||
mod request_stage;
|
mod request_stage;
|
||||||
|
|
||||||
/// Register stages required for requesting and preparing new tiles.
|
/// Register stages required for requesting and preparing new tiles.
|
||||||
pub fn register_stages<HC: HttpClient, SM: ScheduleMethod>(
|
pub fn register_stages<E: Environment>(
|
||||||
schedule: &mut Schedule,
|
schedule: &mut Schedule,
|
||||||
http_source_client: HttpSourceClient<HC>,
|
http_source_client: HttpSourceClient<E::HttpClient>,
|
||||||
scheduler: Box<Scheduler<SM>>,
|
apc: Rc<RefCell<E::AsyncProcedureCall>>,
|
||||||
) {
|
) {
|
||||||
let (message_sender, message_receiver): (MessageSender, MessageReceiver) = mpsc::channel();
|
|
||||||
let shared_thread_state = SharedThreadState {
|
|
||||||
tile_request_state: Arc::new(Mutex::new(TileRequestState::new())),
|
|
||||||
message_sender,
|
|
||||||
geometry_index: Arc::new(Mutex::new(GeometryIndex::new())),
|
|
||||||
};
|
|
||||||
|
|
||||||
schedule.add_stage(
|
schedule.add_stage(
|
||||||
"request",
|
"request",
|
||||||
RequestStage::new(shared_thread_state.clone(), http_source_client, *scheduler),
|
RequestStage::<E>::new(http_source_client, apc.clone()),
|
||||||
);
|
|
||||||
schedule.add_stage(
|
|
||||||
"populate_tile_store",
|
|
||||||
PopulateTileStore::new(shared_thread_state, message_receiver),
|
|
||||||
);
|
);
|
||||||
|
schedule.add_stage("populate_tile_store", PopulateTileStore::<E>::new(apc));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct HeadedPipelineProcessor {
|
pub struct HeadedPipelineProcessor<T: Transferables, HC: HttpClient, C: Context<T, HC>> {
|
||||||
state: SharedThreadState,
|
context: C,
|
||||||
|
phantom_t: PhantomData<T>,
|
||||||
|
phantom_hc: PhantomData<HC>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PipelineProcessor for HeadedPipelineProcessor {
|
impl<'c, T: Transferables, HC: HttpClient, C: Context<T, HC>> PipelineProcessor
|
||||||
fn tile_finished(&mut self, request_id: TileRequestID, coords: &WorldTileCoords) {
|
for HeadedPipelineProcessor<T, HC, C>
|
||||||
self.state
|
{
|
||||||
.message_sender
|
fn tile_finished(&mut self, coords: &WorldTileCoords) {
|
||||||
.send(TessellateMessage::Tile(TileTessellateMessage {
|
self.context
|
||||||
request_id,
|
.send(Message::TileTessellated(T::TileTessellated::new(*coords)))
|
||||||
coords: *coords,
|
|
||||||
}))
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn layer_unavailable(&mut self, coords: &WorldTileCoords, layer_name: &str) {
|
fn layer_unavailable(&mut self, coords: &WorldTileCoords, layer_name: &str) {
|
||||||
self.state
|
self.context
|
||||||
.message_sender
|
.send(Message::UnavailableLayer(T::UnavailableLayer::new(
|
||||||
.send(TessellateMessage::Layer(
|
*coords,
|
||||||
LayerTessellateMessage::UnavailableLayer {
|
layer_name.to_owned(),
|
||||||
coords: *coords,
|
)))
|
||||||
layer_name: layer_name.to_owned(),
|
|
||||||
},
|
|
||||||
))
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn layer_tesselation_finished(
|
fn layer_tesselation_finished(
|
||||||
@ -90,17 +78,13 @@ impl PipelineProcessor for HeadedPipelineProcessor {
|
|||||||
feature_indices: Vec<u32>,
|
feature_indices: Vec<u32>,
|
||||||
layer_data: tile::Layer,
|
layer_data: tile::Layer,
|
||||||
) {
|
) {
|
||||||
self.state
|
self.context
|
||||||
.message_sender
|
.send(Message::TessellatedLayer(T::TessellatedLayer::new(
|
||||||
.send(TessellateMessage::Layer(
|
*coords,
|
||||||
LayerTessellateMessage::TessellatedLayer {
|
buffer,
|
||||||
coords: *coords,
|
feature_indices,
|
||||||
buffer,
|
layer_data,
|
||||||
feature_indices,
|
)))
|
||||||
layer_data,
|
|
||||||
},
|
|
||||||
))
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn layer_indexing_finished(
|
fn layer_indexing_finished(
|
||||||
@ -108,80 +92,32 @@ impl PipelineProcessor for HeadedPipelineProcessor {
|
|||||||
coords: &WorldTileCoords,
|
coords: &WorldTileCoords,
|
||||||
geometries: Vec<IndexedGeometry<f64>>,
|
geometries: Vec<IndexedGeometry<f64>>,
|
||||||
) {
|
) {
|
||||||
if let Ok(mut geometry_index) = self.state.geometry_index.lock() {
|
// FIXME (wasm-executor): Readd
|
||||||
|
/* if let Ok(mut geometry_index) = self.state.geometry_index.lock() {
|
||||||
geometry_index.index_tile(coords, TileIndex::Linear { list: geometries })
|
geometry_index.index_tile(coords, TileIndex::Linear { list: geometries })
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stores and provides access to the thread safe data shared between the schedulers.
|
// FIXME (wasm-executor): Readd
|
||||||
#[derive(Clone)]
|
/*pub fn query_point(
|
||||||
pub struct SharedThreadState {
|
&self,
|
||||||
pub tile_request_state: Arc<Mutex<TileRequestState>>,
|
world_coords: &WorldCoords,
|
||||||
pub message_sender: mpsc::Sender<TessellateMessage>,
|
z: ZoomLevel,
|
||||||
pub geometry_index: Arc<Mutex<GeometryIndex>>,
|
zoom: Zoom,
|
||||||
}
|
) -> Option<Vec<IndexedGeometry<f64>>> {
|
||||||
|
if let Ok(geometry_index) = self.geometry_index.lock() {
|
||||||
impl SharedThreadState {
|
geometry_index
|
||||||
fn get_tile_request(&self, request_id: TileRequestID) -> Option<TileRequest> {
|
.query_point(world_coords, z, zoom)
|
||||||
self.tile_request_state
|
.map(|geometries| {
|
||||||
.lock()
|
geometries
|
||||||
.ok()
|
.iter()
|
||||||
.and_then(|tile_request_state| tile_request_state.get_tile_request(request_id).cloned())
|
.cloned()
|
||||||
|
.cloned()
|
||||||
|
.collect::<Vec<IndexedGeometry<f64>>>()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
}*/
|
||||||
#[tracing::instrument(skip_all)]
|
//}
|
||||||
pub fn process_tile(&self, request_id: TileRequestID, data: Box<[u8]>) -> Result<(), Error> {
|
|
||||||
if let Some(tile_request) = self.get_tile_request(request_id) {
|
|
||||||
let mut pipeline_context = PipelineContext::new(HeadedPipelineProcessor {
|
|
||||||
state: self.clone(),
|
|
||||||
});
|
|
||||||
let pipeline = build_vector_tile_pipeline();
|
|
||||||
pipeline.process((tile_request, request_id, data), &mut pipeline_context);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn tile_unavailable(
|
|
||||||
&self,
|
|
||||||
coords: &WorldTileCoords,
|
|
||||||
request_id: TileRequestID,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
if let Some(tile_request) = self.get_tile_request(request_id) {
|
|
||||||
for to_load in &tile_request.layers {
|
|
||||||
tracing::warn!("layer {} at {} unavailable", to_load, coords);
|
|
||||||
self.message_sender.send(TessellateMessage::Layer(
|
|
||||||
LayerTessellateMessage::UnavailableLayer {
|
|
||||||
coords: tile_request.coords,
|
|
||||||
layer_name: to_load.to_string(),
|
|
||||||
},
|
|
||||||
))?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
|
||||||
pub fn query_point(
|
|
||||||
&self,
|
|
||||||
world_coords: &WorldCoords,
|
|
||||||
z: ZoomLevel,
|
|
||||||
zoom: Zoom,
|
|
||||||
) -> Option<Vec<IndexedGeometry<f64>>> {
|
|
||||||
if let Ok(geometry_index) = self.geometry_index.lock() {
|
|
||||||
geometry_index
|
|
||||||
.query_point(world_coords, z, zoom)
|
|
||||||
.map(|geometries| {
|
|
||||||
geometries
|
|
||||||
.iter()
|
|
||||||
.cloned()
|
|
||||||
.cloned()
|
|
||||||
.collect::<Vec<IndexedGeometry<f64>>>()
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,49 +1,69 @@
|
|||||||
//! Receives data from async threads and populates the [`crate::io::tile_repository::TileRepository`].
|
//! Receives data from async threads and populates the [`crate::io::tile_repository::TileRepository`].
|
||||||
|
|
||||||
use super::{MessageReceiver, SharedThreadState, TessellateMessage, TileTessellateMessage};
|
use std::{borrow::BorrowMut, cell::RefCell, ops::Deref, rc::Rc};
|
||||||
use crate::{context::MapContext, io::tile_repository::StoredLayer, schedule::Stage};
|
|
||||||
|
|
||||||
pub struct PopulateTileStore {
|
use crate::{
|
||||||
shared_thread_state: SharedThreadState,
|
context::MapContext,
|
||||||
message_receiver: MessageReceiver,
|
io::{
|
||||||
|
apc::{AsyncProcedureCall, Message},
|
||||||
|
tile_repository::StoredLayer,
|
||||||
|
transferables::{TessellatedLayer, TileTessellated, UnavailableLayer},
|
||||||
|
},
|
||||||
|
schedule::Stage,
|
||||||
|
Environment,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct PopulateTileStore<E: Environment> {
|
||||||
|
apc: Rc<RefCell<E::AsyncProcedureCall>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PopulateTileStore {
|
impl<E: Environment> PopulateTileStore<E> {
|
||||||
pub fn new(shared_thread_state: SharedThreadState, message_receiver: MessageReceiver) -> Self {
|
pub fn new(apc: Rc<RefCell<E::AsyncProcedureCall>>) -> Self {
|
||||||
Self {
|
Self { apc }
|
||||||
shared_thread_state,
|
|
||||||
message_receiver,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Stage for PopulateTileStore {
|
impl<E: Environment> Stage for PopulateTileStore<E> {
|
||||||
fn run(
|
fn run(
|
||||||
&mut self,
|
&mut self,
|
||||||
MapContext {
|
MapContext {
|
||||||
tile_repository, ..
|
tile_repository, ..
|
||||||
}: &mut MapContext,
|
}: &mut MapContext,
|
||||||
) {
|
) {
|
||||||
if let Ok(result) = self.message_receiver.try_recv() {
|
if let Ok(mut apc) = self.apc.deref().try_borrow_mut() {
|
||||||
match result {
|
if let Some(result) = apc.receive() {
|
||||||
TessellateMessage::Layer(layer_result) => {
|
match result {
|
||||||
let layer: StoredLayer = layer_result.into();
|
Message::TileTessellated(tranferred) => {
|
||||||
tracing::trace!(
|
let coords = tranferred.coords();
|
||||||
"Layer {} at {} reached main thread",
|
tile_repository.success(coords);
|
||||||
layer.layer_name(),
|
|
||||||
layer.get_coords()
|
|
||||||
);
|
|
||||||
tile_repository.put_tessellated_layer(layer);
|
|
||||||
}
|
|
||||||
TessellateMessage::Tile(TileTessellateMessage { request_id, coords }) => loop {
|
|
||||||
if let Ok(mut tile_request_state) =
|
|
||||||
self.shared_thread_state.tile_request_state.try_lock()
|
|
||||||
{
|
|
||||||
tile_request_state.finish_tile_request(request_id);
|
|
||||||
tracing::trace!("Tile at {} finished loading", coords);
|
tracing::trace!("Tile at {} finished loading", coords);
|
||||||
break;
|
log::warn!("Tile at {} finished loading", coords);
|
||||||
}
|
}
|
||||||
},
|
// FIXME: deduplicate
|
||||||
|
Message::UnavailableLayer(tranferred) => {
|
||||||
|
let layer: StoredLayer = tranferred.to_stored_layer();
|
||||||
|
tracing::debug!(
|
||||||
|
"Layer {} at {} reached main thread",
|
||||||
|
layer.layer_name(),
|
||||||
|
layer.get_coords()
|
||||||
|
);
|
||||||
|
tile_repository.put_tessellated_layer(layer);
|
||||||
|
}
|
||||||
|
Message::TessellatedLayer(data) => {
|
||||||
|
let layer: StoredLayer = data.to_stored_layer();
|
||||||
|
tracing::debug!(
|
||||||
|
"Layer {} at {} reached main thread",
|
||||||
|
layer.layer_name(),
|
||||||
|
layer.get_coords()
|
||||||
|
);
|
||||||
|
log::warn!(
|
||||||
|
"Layer {} at {} reached main thread",
|
||||||
|
layer.layer_name(),
|
||||||
|
layer.get_coords()
|
||||||
|
);
|
||||||
|
tile_repository.put_tessellated_layer(layer);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,56 +1,53 @@
|
|||||||
//! Requests tiles which are currently in view
|
//! Requests tiles which are currently in view
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::{
|
||||||
|
borrow::Borrow,
|
||||||
|
cell::RefCell,
|
||||||
|
collections::{HashMap, HashSet},
|
||||||
|
future::Future,
|
||||||
|
ops::Deref,
|
||||||
|
pin::Pin,
|
||||||
|
process::Output,
|
||||||
|
rc::Rc,
|
||||||
|
str::FromStr,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
context::MapContext,
|
context::MapContext,
|
||||||
coords::{ViewRegion, WorldTileCoords},
|
coords::{ViewRegion, WorldTileCoords, ZoomLevel},
|
||||||
error::Error,
|
error::Error,
|
||||||
io::{
|
io::{
|
||||||
|
apc::{AsyncProcedureCall, AsyncProcedureFuture, Context, Input, Message},
|
||||||
|
pipeline::{PipelineContext, Processable},
|
||||||
source_client::{HttpSourceClient, SourceClient},
|
source_client::{HttpSourceClient, SourceClient},
|
||||||
|
tile_pipelines::build_vector_tile_pipeline,
|
||||||
tile_repository::TileRepository,
|
tile_repository::TileRepository,
|
||||||
|
transferables::{Transferables, UnavailableLayer},
|
||||||
TileRequest,
|
TileRequest,
|
||||||
},
|
},
|
||||||
schedule::Stage,
|
schedule::Stage,
|
||||||
stages::SharedThreadState,
|
stages::HeadedPipelineProcessor,
|
||||||
HttpClient, ScheduleMethod, Scheduler, Style,
|
Environment, HttpClient, Scheduler, Style,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct RequestStage<SM, HC>
|
pub struct RequestStage<E: Environment> {
|
||||||
where
|
apc: Rc<RefCell<E::AsyncProcedureCall>>,
|
||||||
SM: ScheduleMethod,
|
http_source_client: HttpSourceClient<E::HttpClient>,
|
||||||
HC: HttpClient,
|
|
||||||
{
|
|
||||||
shared_thread_state: SharedThreadState,
|
|
||||||
scheduler: Scheduler<SM>,
|
|
||||||
http_source_client: HttpSourceClient<HC>,
|
|
||||||
try_failed: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SM, HC> RequestStage<SM, HC>
|
impl<E: Environment> RequestStage<E> {
|
||||||
where
|
|
||||||
SM: ScheduleMethod,
|
|
||||||
HC: HttpClient,
|
|
||||||
{
|
|
||||||
pub fn new(
|
pub fn new(
|
||||||
shared_thread_state: SharedThreadState,
|
http_source_client: HttpSourceClient<E::HttpClient>,
|
||||||
http_source_client: HttpSourceClient<HC>,
|
apc: Rc<RefCell<E::AsyncProcedureCall>>,
|
||||||
scheduler: Scheduler<SM>,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
shared_thread_state,
|
apc,
|
||||||
scheduler,
|
|
||||||
http_source_client,
|
http_source_client,
|
||||||
try_failed: false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SM, HC> Stage for RequestStage<SM, HC>
|
impl<E: Environment> Stage for RequestStage<E> {
|
||||||
where
|
|
||||||
SM: ScheduleMethod,
|
|
||||||
HC: HttpClient,
|
|
||||||
{
|
|
||||||
fn run(
|
fn run(
|
||||||
&mut self,
|
&mut self,
|
||||||
MapContext {
|
MapContext {
|
||||||
@ -62,11 +59,10 @@ where
|
|||||||
) {
|
) {
|
||||||
let view_region = view_state.create_view_region();
|
let view_region = view_state.create_view_region();
|
||||||
|
|
||||||
if view_state.camera.did_change(0.05) || view_state.zoom.did_change(0.05) || self.try_failed
|
if view_state.camera.did_change(0.05) || view_state.zoom.did_change(0.05) {
|
||||||
{
|
|
||||||
if let Some(view_region) = &view_region {
|
if let Some(view_region) = &view_region {
|
||||||
// FIXME: We also need to request tiles from layers above if we are over the maximum zoom level
|
// FIXME: We also need to request tiles from layers above if we are over the maximum zoom level
|
||||||
self.try_failed = self.request_tiles_in_view(tile_repository, style, view_region);
|
self.request_tiles_in_view(tile_repository, style, view_region);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,20 +71,58 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SM, HC> RequestStage<SM, HC>
|
pub fn schedule<E: Environment, C: Context<E::Transferables, E::HttpClient>>(
|
||||||
where
|
input: Input,
|
||||||
SM: ScheduleMethod,
|
context: C,
|
||||||
HC: HttpClient,
|
) -> AsyncProcedureFuture {
|
||||||
{
|
// FIXME: improve input handling
|
||||||
|
let input = match input {
|
||||||
|
Input::TileRequest(input) => Some(input),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
.unwrap(); // FIXME (wasm-executor): Remove unwrap
|
||||||
|
|
||||||
|
Box::pin(async move {
|
||||||
|
let coords = input.coords;
|
||||||
|
let client = context.source_client();
|
||||||
|
|
||||||
|
match client.fetch(&coords).await {
|
||||||
|
Ok(data) => {
|
||||||
|
let data = data.into_boxed_slice();
|
||||||
|
|
||||||
|
let mut pipeline_context = PipelineContext::new(HeadedPipelineProcessor {
|
||||||
|
context,
|
||||||
|
phantom_t: Default::default(),
|
||||||
|
phantom_hc: Default::default(),
|
||||||
|
});
|
||||||
|
let pipeline = build_vector_tile_pipeline();
|
||||||
|
pipeline.process((input, data), &mut pipeline_context);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("{:?}", &e);
|
||||||
|
for to_load in &input.layers {
|
||||||
|
tracing::warn!("layer {} at {} unavailable", to_load, coords);
|
||||||
|
context.send(Message::UnavailableLayer(
|
||||||
|
<E::Transferables as Transferables>::UnavailableLayer::new(
|
||||||
|
input.coords,
|
||||||
|
to_load.to_string(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Environment> RequestStage<E> {
|
||||||
/// Request tiles which are currently in view.
|
/// Request tiles which are currently in view.
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
fn request_tiles_in_view(
|
fn request_tiles_in_view(
|
||||||
&self,
|
&self,
|
||||||
tile_repository: &TileRepository,
|
tile_repository: &mut TileRepository,
|
||||||
style: &Style,
|
style: &Style,
|
||||||
view_region: &ViewRegion,
|
view_region: &ViewRegion,
|
||||||
) -> bool {
|
) {
|
||||||
let mut try_failed = false;
|
|
||||||
let source_layers: HashSet<String> = style
|
let source_layers: HashSet<String> = style
|
||||||
.layers
|
.layers
|
||||||
.iter()
|
.iter()
|
||||||
@ -98,66 +132,41 @@ where
|
|||||||
for coords in view_region.iter() {
|
for coords in view_region.iter() {
|
||||||
if coords.build_quad_key().is_some() {
|
if coords.build_quad_key().is_some() {
|
||||||
// TODO: Make tesselation depend on style?
|
// TODO: Make tesselation depend on style?
|
||||||
try_failed = self
|
self.request_tile(tile_repository, &coords, &source_layers)
|
||||||
.try_request_tile(tile_repository, &coords, &source_layers)
|
.unwrap(); // TODO: Remove unwrap
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try_failed
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_request_tile(
|
fn request_tile(
|
||||||
&self,
|
&self,
|
||||||
tile_repository: &TileRepository,
|
tile_repository: &mut TileRepository,
|
||||||
coords: &WorldTileCoords,
|
coords: &WorldTileCoords,
|
||||||
layers: &HashSet<String>,
|
layers: &HashSet<String>,
|
||||||
) -> Result<bool, Error> {
|
) -> Result<(), Error> {
|
||||||
if !tile_repository.is_layers_missing(coords, layers) {
|
/* if !tile_repository.is_layers_missing(coords, layers) {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
if tile_repository.needs_fetching(&coords) {
|
||||||
|
tile_repository.create_tile(coords);
|
||||||
|
|
||||||
|
tracing::info!("new tile request: {}", &coords);
|
||||||
|
self.apc.deref().borrow().schedule(
|
||||||
|
Input::TileRequest(TileRequest {
|
||||||
|
coords: *coords,
|
||||||
|
layers: layers.clone(),
|
||||||
|
}),
|
||||||
|
schedule::<
|
||||||
|
E,
|
||||||
|
<E::AsyncProcedureCall as AsyncProcedureCall<
|
||||||
|
E::Transferables,
|
||||||
|
E::HttpClient,
|
||||||
|
>>::Context,
|
||||||
|
>,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(mut tile_request_state) = self.shared_thread_state.tile_request_state.try_lock() {
|
Ok(())
|
||||||
if let Some(request_id) = tile_request_state.start_tile_request(TileRequest {
|
|
||||||
coords: *coords,
|
|
||||||
layers: layers.clone(),
|
|
||||||
}) {
|
|
||||||
tracing::info!("new tile request: {}", &coords);
|
|
||||||
|
|
||||||
// The following snippet can be added instead of the next code block to demonstrate
|
|
||||||
// an understanable approach of fetching
|
|
||||||
/*#[cfg(target_arch = "wasm32")]
|
|
||||||
if let Some(tile_coords) = coords.into_tile(TileAddressingScheme::TMS) {
|
|
||||||
crate::platform::legacy_webworker_fetcher::request_tile(
|
|
||||||
request_id,
|
|
||||||
tile_coords,
|
|
||||||
);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
let client = SourceClient::Http(self.http_source_client.clone());
|
|
||||||
let coords = *coords;
|
|
||||||
|
|
||||||
let state = self.shared_thread_state.clone();
|
|
||||||
self.scheduler
|
|
||||||
.schedule_method()
|
|
||||||
.schedule(Box::new(move || {
|
|
||||||
Box::pin(async move {
|
|
||||||
match client.fetch(&coords).await {
|
|
||||||
Ok(data) => state
|
|
||||||
.process_tile(request_id, data.into_boxed_slice())
|
|
||||||
.unwrap(),
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("{:?}", &e);
|
|
||||||
state.tile_unavailable(&coords, request_id).unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}))
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(false)
|
|
||||||
} else {
|
|
||||||
Ok(true)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -56,6 +56,21 @@ impl<V, I> OverAlignedVertexBuffer<V, I> {
|
|||||||
usable_indices: 0,
|
usable_indices: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_slices(vertices: &[V], indices: &[I], usable_indices: u32) -> Self
|
||||||
|
where
|
||||||
|
V: Copy,
|
||||||
|
I: Copy,
|
||||||
|
{
|
||||||
|
// FIXME (wasm-executor), make this fn not needed
|
||||||
|
let mut buffers = VertexBuffers::with_capacity(0, 0);
|
||||||
|
buffers.vertices = Vec::from(vertices);
|
||||||
|
buffers.indices = Vec::from(indices);
|
||||||
|
Self {
|
||||||
|
buffer: buffers,
|
||||||
|
usable_indices,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: Pod, I: Pod> From<VertexBuffers<V, I>> for OverAlignedVertexBuffer<V, I> {
|
impl<V: Pod, I: Pod> From<VertexBuffers<V, I>> for OverAlignedVertexBuffer<V, I> {
|
||||||
|
|||||||
@ -64,7 +64,7 @@ impl<I: std::ops::Add + From<lyon::tessellation::VertexId> + MaxIndex> ZeroTesse
|
|||||||
&StrokeOptions::tolerance(DEFAULT_TOLERANCE),
|
&StrokeOptions::tolerance(DEFAULT_TOLERANCE),
|
||||||
&mut BuffersBuilder::new(&mut self.buffer, VertexConstructor {}),
|
&mut BuffersBuilder::new(&mut self.buffer, VertexConstructor {}),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap(); // TODO: Remove unwrap
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end(&mut self, close: bool) {
|
fn end(&mut self, close: bool) {
|
||||||
@ -83,7 +83,7 @@ impl<I: std::ops::Add + From<lyon::tessellation::VertexId> + MaxIndex> ZeroTesse
|
|||||||
&FillOptions::tolerance(DEFAULT_TOLERANCE).with_fill_rule(FillRule::NonZero),
|
&FillOptions::tolerance(DEFAULT_TOLERANCE).with_fill_rule(FillRule::NonZero),
|
||||||
&mut BuffersBuilder::new(&mut self.buffer, VertexConstructor {}),
|
&mut BuffersBuilder::new(&mut self.buffer, VertexConstructor {}),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap(); // TODO: Remove unwrap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
//! Utilities for the window system.
|
//! Utilities for the window system.
|
||||||
|
|
||||||
|
use std::{cell::RefCell, rc::Rc};
|
||||||
|
|
||||||
use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle};
|
use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle};
|
||||||
|
|
||||||
use crate::{HttpClient, InteractiveMapSchedule, ScheduleMethod};
|
use crate::{Environment, HttpClient, InteractiveMapSchedule};
|
||||||
|
|
||||||
/// Window of a certain [`WindowSize`]. This can either be a proper window or a headless one.
|
/// Window of a certain [`WindowSize`]. This can either be a proper window or a headless one.
|
||||||
pub trait MapWindow {
|
pub trait MapWindow {
|
||||||
@ -27,13 +29,9 @@ pub trait MapWindowConfig: 'static {
|
|||||||
|
|
||||||
/// The event loop is responsible for processing events and propagating them to the map renderer.
|
/// The event loop is responsible for processing events and propagating them to the map renderer.
|
||||||
/// Only non-headless windows use an [`EventLoop`].
|
/// Only non-headless windows use an [`EventLoop`].
|
||||||
pub trait EventLoop<MWC, SM, HC>
|
pub trait EventLoop<E: Environment> {
|
||||||
where
|
// FIXME (wasm-executor): Avoid Rc, change ownership model
|
||||||
MWC: MapWindowConfig,
|
fn run(self, map_schedule: Rc<RefCell<InteractiveMapSchedule<E>>>, max_frames: Option<u64>);
|
||||||
SM: ScheduleMethod,
|
|
||||||
HC: HttpClient,
|
|
||||||
{
|
|
||||||
fn run(self, map_schedule: InteractiveMapSchedule<MWC, SM, HC>, max_frames: Option<u64>);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Window size with a width and an height in pixels.
|
/// Window size with a width and an height in pixels.
|
||||||
|
|||||||
@ -1,7 +1,2 @@
|
|||||||
[toolchain]
|
[toolchain]
|
||||||
channel = "1.62"
|
channel = "1.62"
|
||||||
targets = [
|
|
||||||
"wasm32-unknown-unknown", "x86_64-unknown-linux-gnu", "x86_64-linux-android", "aarch64-linux-android",
|
|
||||||
"x86_64-apple-darwin", "aarch64-apple-darwin", "x86_64-apple-ios", "aarch64-apple-ios", "aarch64-apple-ios-sim"
|
|
||||||
]
|
|
||||||
components = [ "rust-src" ] # rust-src is required for WASM and android builds which recompile the stdlib
|
|
||||||
|
|||||||
@ -37,7 +37,11 @@ js-sys = "0.3.58"
|
|||||||
wasm-bindgen = "0.2.81"
|
wasm-bindgen = "0.2.81"
|
||||||
wasm-bindgen-futures = "0.4.31"
|
wasm-bindgen-futures = "0.4.31"
|
||||||
console_log = { version = "0.2.0", features = ["color"] }
|
console_log = { version = "0.2.0", features = ["color"] }
|
||||||
tracing-wasm = { version = "0.2.1", optional = true } # FIXME: Low quality dependency
|
tracing-wasm = { version = "0.2.1", optional = true } # TODO: Low quality dependency
|
||||||
|
# For passing Inputs in AsyncProcedureCalls
|
||||||
|
serde_json = "1.0.85"
|
||||||
|
bytemuck = "1.12.1" # FIXME (wasm-executor): Remove
|
||||||
|
bytemuck_derive = "1.2.1" # FIXME (wasm-executor): Remove
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
wasm-bindgen-test = "0.3.31"
|
wasm-bindgen-test = "0.3.31"
|
||||||
|
|||||||
303
web/demo/package-lock.json
generated
303
web/demo/package-lock.json
generated
@ -12,11 +12,14 @@
|
|||||||
"maplibre-rs": "file:../lib"
|
"maplibre-rs": "file:../lib"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/node": "^18.7.20",
|
||||||
|
"@types/webpack": "^5.28.0",
|
||||||
"copy-webpack-plugin": "^10.2.4",
|
"copy-webpack-plugin": "^10.2.4",
|
||||||
"file-loader": "^6.2.0",
|
"file-loader": "^6.2.0",
|
||||||
"html-webpack-plugin": "^5.5.0",
|
"html-webpack-plugin": "^5.5.0",
|
||||||
"ts-loader": "^9.2.6",
|
"ts-loader": "^9.2.6",
|
||||||
"typescript": "^4.5.4",
|
"ts-node": "^10.9.1",
|
||||||
|
"typescript": "^4.8.3",
|
||||||
"webpack": "^5.65.0",
|
"webpack": "^5.65.0",
|
||||||
"webpack-cli": "^4.9.1",
|
"webpack-cli": "^4.9.1",
|
||||||
"webpack-dev-server": "^4.6.0"
|
"webpack-dev-server": "^4.6.0"
|
||||||
@ -27,6 +30,7 @@
|
|||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"binaryen": "^110.0.0",
|
||||||
"spectorjs": "^0.9.27",
|
"spectorjs": "^0.9.27",
|
||||||
"wasm-feature-detect": "^1.2.11"
|
"wasm-feature-detect": "^1.2.11"
|
||||||
},
|
},
|
||||||
@ -36,10 +40,31 @@
|
|||||||
"esbuild": "^0.14.38",
|
"esbuild": "^0.14.38",
|
||||||
"esbuild-plugin-inline-worker": "^0.1.1",
|
"esbuild-plugin-inline-worker": "^0.1.1",
|
||||||
"typescript": "^4.5.4",
|
"typescript": "^4.5.4",
|
||||||
"wasm-pack": "^0.10.2",
|
|
||||||
"yargs": "^17.5.1"
|
"yargs": "^17.5.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@cspotcode/source-map-support": {
|
||||||
|
"version": "0.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
|
||||||
|
"integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@jridgewell/trace-mapping": "0.3.9"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": {
|
||||||
|
"version": "0.3.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
|
||||||
|
"integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@jridgewell/resolve-uri": "^3.0.3",
|
||||||
|
"@jridgewell/sourcemap-codec": "^1.4.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@discoveryjs/json-ext": {
|
"node_modules/@discoveryjs/json-ext": {
|
||||||
"version": "0.5.7",
|
"version": "0.5.7",
|
||||||
"resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz",
|
"resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz",
|
||||||
@ -148,6 +173,30 @@
|
|||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@tsconfig/node10": {
|
||||||
|
"version": "1.0.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
|
||||||
|
"integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/@tsconfig/node12": {
|
||||||
|
"version": "1.0.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
|
||||||
|
"integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/@tsconfig/node14": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/@tsconfig/node16": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@types/body-parser": {
|
"node_modules/@types/body-parser": {
|
||||||
"version": "1.19.2",
|
"version": "1.19.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz",
|
||||||
@ -263,9 +312,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "18.7.15",
|
"version": "18.7.20",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.15.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.20.tgz",
|
||||||
"integrity": "sha512-XnjpaI8Bgc3eBag2Aw4t2Uj/49lLBSStHWfqKvIuXD7FIrZyMLWp8KuAFHAqxMZYTF9l08N1ctUn9YNybZJVmQ==",
|
"integrity": "sha512-adzY4vLLr5Uivmx8+zfSJ5fbdgKxX8UMtjtl+17n0B1q1Nz8JEmE151vefMdpD+1gyh+77weN4qEhej/O7budQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/qs": {
|
"node_modules/@types/qs": {
|
||||||
@ -314,6 +363,17 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/webpack": {
|
||||||
|
"version": "5.28.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-5.28.0.tgz",
|
||||||
|
"integrity": "sha512-8cP0CzcxUiFuA9xGJkfeVpqmWTk9nx6CWwamRGCj95ph1SmlRRk9KlCZ6avhCbZd4L68LvYT6l1kpdEnQXrF8w==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*",
|
||||||
|
"tapable": "^2.2.0",
|
||||||
|
"webpack": "^5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/ws": {
|
"node_modules/@types/ws": {
|
||||||
"version": "8.5.3",
|
"version": "8.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz",
|
||||||
@ -551,6 +611,15 @@
|
|||||||
"acorn": "^8"
|
"acorn": "^8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/acorn-walk": {
|
||||||
|
"version": "8.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
|
||||||
|
"integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ajv": {
|
"node_modules/ajv": {
|
||||||
"version": "8.11.0",
|
"version": "8.11.0",
|
||||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz",
|
||||||
@ -645,6 +714,12 @@
|
|||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/arg": {
|
||||||
|
"version": "4.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
|
||||||
|
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/array-flatten": {
|
"node_modules/array-flatten": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz",
|
||||||
@ -1088,6 +1163,12 @@
|
|||||||
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
|
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/create-require": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/cross-spawn": {
|
"node_modules/cross-spawn": {
|
||||||
"version": "7.0.3",
|
"version": "7.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||||
@ -1185,6 +1266,15 @@
|
|||||||
"integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==",
|
"integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/diff": {
|
||||||
|
"version": "4.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
|
||||||
|
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.3.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/dir-glob": {
|
"node_modules/dir-glob": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
|
||||||
@ -2424,6 +2514,12 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/make-error": {
|
||||||
|
"version": "1.3.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
|
||||||
|
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/maplibre-rs": {
|
"node_modules/maplibre-rs": {
|
||||||
"resolved": "../lib",
|
"resolved": "../lib",
|
||||||
"link": true
|
"link": true
|
||||||
@ -3768,6 +3864,49 @@
|
|||||||
"webpack": "^5.0.0"
|
"webpack": "^5.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ts-node": {
|
||||||
|
"version": "10.9.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz",
|
||||||
|
"integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@cspotcode/source-map-support": "^0.8.0",
|
||||||
|
"@tsconfig/node10": "^1.0.7",
|
||||||
|
"@tsconfig/node12": "^1.0.7",
|
||||||
|
"@tsconfig/node14": "^1.0.0",
|
||||||
|
"@tsconfig/node16": "^1.0.2",
|
||||||
|
"acorn": "^8.4.1",
|
||||||
|
"acorn-walk": "^8.1.1",
|
||||||
|
"arg": "^4.1.0",
|
||||||
|
"create-require": "^1.1.0",
|
||||||
|
"diff": "^4.0.1",
|
||||||
|
"make-error": "^1.1.1",
|
||||||
|
"v8-compile-cache-lib": "^3.0.1",
|
||||||
|
"yn": "3.1.1"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"ts-node": "dist/bin.js",
|
||||||
|
"ts-node-cwd": "dist/bin-cwd.js",
|
||||||
|
"ts-node-esm": "dist/bin-esm.js",
|
||||||
|
"ts-node-script": "dist/bin-script.js",
|
||||||
|
"ts-node-transpile-only": "dist/bin-transpile.js",
|
||||||
|
"ts-script": "dist/bin-script-deprecated.js"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@swc/core": ">=1.2.50",
|
||||||
|
"@swc/wasm": ">=1.2.50",
|
||||||
|
"@types/node": "*",
|
||||||
|
"typescript": ">=2.7"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@swc/core": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@swc/wasm": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/tslib": {
|
"node_modules/tslib": {
|
||||||
"version": "2.4.0",
|
"version": "2.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
|
||||||
@ -3788,9 +3927,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/typescript": {
|
"node_modules/typescript": {
|
||||||
"version": "4.8.2",
|
"version": "4.8.3",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.2.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz",
|
||||||
"integrity": "sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw==",
|
"integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
@ -3874,6 +4013,12 @@
|
|||||||
"uuid": "dist/bin/uuid"
|
"uuid": "dist/bin/uuid"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/v8-compile-cache-lib": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/vary": {
|
"node_modules/vary": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||||
@ -4233,9 +4378,39 @@
|
|||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||||
"dev": true
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/yn": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@cspotcode/source-map-support": {
|
||||||
|
"version": "0.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
|
||||||
|
"integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@jridgewell/trace-mapping": "0.3.9"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@jridgewell/trace-mapping": {
|
||||||
|
"version": "0.3.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
|
||||||
|
"integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@jridgewell/resolve-uri": "^3.0.3",
|
||||||
|
"@jridgewell/sourcemap-codec": "^1.4.10"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"@discoveryjs/json-ext": {
|
"@discoveryjs/json-ext": {
|
||||||
"version": "0.5.7",
|
"version": "0.5.7",
|
||||||
"resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz",
|
"resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz",
|
||||||
@ -4323,6 +4498,30 @@
|
|||||||
"fastq": "^1.6.0"
|
"fastq": "^1.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@tsconfig/node10": {
|
||||||
|
"version": "1.0.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
|
||||||
|
"integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"@tsconfig/node12": {
|
||||||
|
"version": "1.0.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
|
||||||
|
"integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"@tsconfig/node14": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"@tsconfig/node16": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"@types/body-parser": {
|
"@types/body-parser": {
|
||||||
"version": "1.19.2",
|
"version": "1.19.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz",
|
||||||
@ -4438,9 +4637,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "18.7.15",
|
"version": "18.7.20",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.15.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.20.tgz",
|
||||||
"integrity": "sha512-XnjpaI8Bgc3eBag2Aw4t2Uj/49lLBSStHWfqKvIuXD7FIrZyMLWp8KuAFHAqxMZYTF9l08N1ctUn9YNybZJVmQ==",
|
"integrity": "sha512-adzY4vLLr5Uivmx8+zfSJ5fbdgKxX8UMtjtl+17n0B1q1Nz8JEmE151vefMdpD+1gyh+77weN4qEhej/O7budQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/qs": {
|
"@types/qs": {
|
||||||
@ -4489,6 +4688,17 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/webpack": {
|
||||||
|
"version": "5.28.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-5.28.0.tgz",
|
||||||
|
"integrity": "sha512-8cP0CzcxUiFuA9xGJkfeVpqmWTk9nx6CWwamRGCj95ph1SmlRRk9KlCZ6avhCbZd4L68LvYT6l1kpdEnQXrF8w==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "*",
|
||||||
|
"tapable": "^2.2.0",
|
||||||
|
"webpack": "^5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/ws": {
|
"@types/ws": {
|
||||||
"version": "8.5.3",
|
"version": "8.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz",
|
||||||
@ -4702,6 +4912,12 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {}
|
"requires": {}
|
||||||
},
|
},
|
||||||
|
"acorn-walk": {
|
||||||
|
"version": "8.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
|
||||||
|
"integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"ajv": {
|
"ajv": {
|
||||||
"version": "8.11.0",
|
"version": "8.11.0",
|
||||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz",
|
||||||
@ -4763,6 +4979,12 @@
|
|||||||
"picomatch": "^2.0.4"
|
"picomatch": "^2.0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"arg": {
|
||||||
|
"version": "4.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
|
||||||
|
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"array-flatten": {
|
"array-flatten": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz",
|
||||||
@ -5095,6 +5317,12 @@
|
|||||||
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
|
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"create-require": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"cross-spawn": {
|
"cross-spawn": {
|
||||||
"version": "7.0.3",
|
"version": "7.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||||
@ -5167,6 +5395,12 @@
|
|||||||
"integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==",
|
"integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"diff": {
|
||||||
|
"version": "4.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
|
||||||
|
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"dir-glob": {
|
"dir-glob": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
|
||||||
@ -6097,17 +6331,23 @@
|
|||||||
"yallist": "^4.0.0"
|
"yallist": "^4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"make-error": {
|
||||||
|
"version": "1.3.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
|
||||||
|
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"maplibre-rs": {
|
"maplibre-rs": {
|
||||||
"version": "file:../lib",
|
"version": "file:../lib",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@chialab/esbuild-plugin-meta-url": "^0.15.28",
|
"@chialab/esbuild-plugin-meta-url": "^0.15.28",
|
||||||
|
"binaryen": "^110.0.0",
|
||||||
"chokidar": "^3.5.3",
|
"chokidar": "^3.5.3",
|
||||||
"esbuild": "^0.14.38",
|
"esbuild": "^0.14.38",
|
||||||
"esbuild-plugin-inline-worker": "^0.1.1",
|
"esbuild-plugin-inline-worker": "^0.1.1",
|
||||||
"spectorjs": "^0.9.27",
|
"spectorjs": "^0.9.27",
|
||||||
"typescript": "^4.5.4",
|
"typescript": "^4.5.4",
|
||||||
"wasm-feature-detect": "^1.2.11",
|
"wasm-feature-detect": "^1.2.11",
|
||||||
"wasm-pack": "^0.10.2",
|
|
||||||
"yargs": "^17.5.1"
|
"yargs": "^17.5.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -7102,6 +7342,27 @@
|
|||||||
"semver": "^7.3.4"
|
"semver": "^7.3.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ts-node": {
|
||||||
|
"version": "10.9.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz",
|
||||||
|
"integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@cspotcode/source-map-support": "^0.8.0",
|
||||||
|
"@tsconfig/node10": "^1.0.7",
|
||||||
|
"@tsconfig/node12": "^1.0.7",
|
||||||
|
"@tsconfig/node14": "^1.0.0",
|
||||||
|
"@tsconfig/node16": "^1.0.2",
|
||||||
|
"acorn": "^8.4.1",
|
||||||
|
"acorn-walk": "^8.1.1",
|
||||||
|
"arg": "^4.1.0",
|
||||||
|
"create-require": "^1.1.0",
|
||||||
|
"diff": "^4.0.1",
|
||||||
|
"make-error": "^1.1.1",
|
||||||
|
"v8-compile-cache-lib": "^3.0.1",
|
||||||
|
"yn": "3.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"tslib": {
|
"tslib": {
|
||||||
"version": "2.4.0",
|
"version": "2.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
|
||||||
@ -7119,9 +7380,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"typescript": {
|
"typescript": {
|
||||||
"version": "4.8.2",
|
"version": "4.8.3",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.2.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz",
|
||||||
"integrity": "sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw==",
|
"integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"unpipe": {
|
"unpipe": {
|
||||||
@ -7173,6 +7434,12 @@
|
|||||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"v8-compile-cache-lib": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"vary": {
|
"vary": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||||
@ -7412,6 +7679,12 @@
|
|||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||||
"dev": true
|
"dev": true
|
||||||
|
},
|
||||||
|
"yn": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
|
||||||
|
"dev": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,11 +20,14 @@
|
|||||||
"maplibre-rs": "file:../lib"
|
"maplibre-rs": "file:../lib"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/node": "^18.7.20",
|
||||||
|
"@types/webpack": "^5.28.0",
|
||||||
"copy-webpack-plugin": "^10.2.4",
|
"copy-webpack-plugin": "^10.2.4",
|
||||||
"file-loader": "^6.2.0",
|
"file-loader": "^6.2.0",
|
||||||
"html-webpack-plugin": "^5.5.0",
|
"html-webpack-plugin": "^5.5.0",
|
||||||
"ts-loader": "^9.2.6",
|
"ts-loader": "^9.2.6",
|
||||||
"typescript": "^4.5.4",
|
"ts-node": "^10.9.1",
|
||||||
|
"typescript": "^4.8.3",
|
||||||
"webpack": "^5.65.0",
|
"webpack": "^5.65.0",
|
||||||
"webpack-cli": "^4.9.1",
|
"webpack-cli": "^4.9.1",
|
||||||
"webpack-dev-server": "^4.6.0"
|
"webpack-dev-server": "^4.6.0"
|
||||||
|
|||||||
@ -6,5 +6,10 @@
|
|||||||
"target": "es5",
|
"target": "es5",
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"moduleResolution": "node"
|
"moduleResolution": "node"
|
||||||
|
},
|
||||||
|
"ts-node": {
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "CommonJS"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,17 +1,17 @@
|
|||||||
const path = require("path");
|
import * as path from 'path';
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
import * as webpack from 'webpack';
|
||||||
//const CopyPlugin = require("copy-webpack-plugin");
|
import * as HtmlWebpackPlugin from 'html-webpack-plugin';
|
||||||
const webpack = require("webpack");
|
|
||||||
|
|
||||||
let dist = path.join(__dirname, 'dist/');
|
let dist = path.join(__dirname, 'dist/');
|
||||||
module.exports = (env) => ({
|
const config: (env: any) => webpack.Configuration = (env) => ({
|
||||||
mode: "development",
|
mode: "development",
|
||||||
entry: {
|
entry: {
|
||||||
main: "./index.ts",
|
main: "./index.ts",
|
||||||
},
|
},
|
||||||
experiments: {
|
experiments: {
|
||||||
asyncWebAssembly: env.cjs ? false : true
|
asyncWebAssembly: !env.cjs
|
||||||
},
|
},
|
||||||
|
stats: 'minimal',
|
||||||
performance: {
|
performance: {
|
||||||
maxEntrypointSize: 400000,
|
maxEntrypointSize: 400000,
|
||||||
maxAssetSize: 400000000,
|
maxAssetSize: 400000000,
|
||||||
@ -65,4 +65,6 @@ module.exports = (env) => ({
|
|||||||
title: 'maplibre demo',
|
title: 'maplibre demo',
|
||||||
}),
|
}),
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export default config;
|
||||||
4
web/lib/.gitignore
vendored
4
web/lib/.gitignore
vendored
@ -4,6 +4,6 @@ libs/maplibre*
|
|||||||
|
|
||||||
dist
|
dist
|
||||||
|
|
||||||
src/wasm-pack
|
src/wasm
|
||||||
|
|
||||||
.parcel-cache
|
.parcel-cache
|
||||||
|
|||||||
1
web/lib/@types/env/index.d.ts
vendored
1
web/lib/@types/env/index.d.ts
vendored
@ -1 +1,2 @@
|
|||||||
declare const WEBGL: boolean
|
declare const WEBGL: boolean
|
||||||
|
declare const MULTITHREADED: boolean
|
||||||
|
|||||||
@ -2,35 +2,38 @@ import {build} from 'esbuild';
|
|||||||
import metaUrlPlugin from '@chialab/esbuild-plugin-meta-url';
|
import metaUrlPlugin from '@chialab/esbuild-plugin-meta-url';
|
||||||
import inlineWorker from 'esbuild-plugin-inline-worker';
|
import inlineWorker from 'esbuild-plugin-inline-worker';
|
||||||
import yargs from "yargs";
|
import yargs from "yargs";
|
||||||
|
import process from "process";
|
||||||
import chokidar from "chokidar";
|
import chokidar from "chokidar";
|
||||||
import {spawnSync} from "child_process"
|
import {spawnSync} from "child_process"
|
||||||
import {unlink} from "fs";
|
|
||||||
import {dirname} from "path";
|
import {dirname} from "path";
|
||||||
import {fileURLToPath} from "url";
|
import {fileURLToPath} from "url";
|
||||||
|
|
||||||
let argv = yargs(process.argv.slice(2))
|
let argv = yargs(process.argv.slice(2))
|
||||||
.option('watch', {
|
.option('watch', {
|
||||||
alias: 'w',
|
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
description: 'Enable watching'
|
description: 'Enable watching'
|
||||||
})
|
})
|
||||||
|
.option('release', {
|
||||||
|
type: 'boolean',
|
||||||
|
description: 'Release mode'
|
||||||
|
})
|
||||||
.option('webgl', {
|
.option('webgl', {
|
||||||
alias: 'g',
|
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
description: 'Enable webgl'
|
description: 'Enable webgl'
|
||||||
})
|
})
|
||||||
|
.option('multithreaded', {
|
||||||
|
type: 'boolean',
|
||||||
|
description: 'Enable multithreaded support'
|
||||||
|
})
|
||||||
.option('esm', {
|
.option('esm', {
|
||||||
alias: 'e',
|
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
description: 'Enable esm'
|
description: 'Enable esm'
|
||||||
})
|
})
|
||||||
.option('cjs', {
|
.option('cjs', {
|
||||||
alias: 'c',
|
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
description: 'Enable cjs'
|
description: 'Enable cjs'
|
||||||
})
|
})
|
||||||
.option('iife', {
|
.option('iife', {
|
||||||
alias: 'i',
|
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
description: 'Enable iife'
|
description: 'Enable iife'
|
||||||
})
|
})
|
||||||
@ -39,6 +42,8 @@ let argv = yargs(process.argv.slice(2))
|
|||||||
let esm = argv.esm;
|
let esm = argv.esm;
|
||||||
let iife = argv.iife;
|
let iife = argv.iife;
|
||||||
let cjs = argv.cjs;
|
let cjs = argv.cjs;
|
||||||
|
let release = argv.release;
|
||||||
|
let multithreaded = argv.multithreaded;
|
||||||
|
|
||||||
if (!esm && !iife && !cjs) {
|
if (!esm && !iife && !cjs) {
|
||||||
console.warn("Enabling ESM bundling as no other bundle is enabled.")
|
console.warn("Enabling ESM bundling as no other bundle is enabled.")
|
||||||
@ -51,19 +56,29 @@ if (webgl) {
|
|||||||
console.log("WebGL support enabled.")
|
console.log("WebGL support enabled.")
|
||||||
}
|
}
|
||||||
|
|
||||||
let baseSettings = {
|
if (multithreaded) {
|
||||||
entryPoints: ['src/index.ts'],
|
console.log("multithreaded support enabled.")
|
||||||
bundle: true,
|
}
|
||||||
|
|
||||||
|
let baseConfig = {
|
||||||
platform: "browser",
|
platform: "browser",
|
||||||
|
bundle: true,
|
||||||
assetNames: "assets/[name]",
|
assetNames: "assets/[name]",
|
||||||
define: {"WEBGL": `${webgl}`},
|
define: {
|
||||||
|
WEBGL: `${webgl}`,
|
||||||
|
MULTITHREADED: `${multithreaded}`
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
let config = {
|
||||||
|
...baseConfig,
|
||||||
|
entryPoints:['src/index.ts'],
|
||||||
incremental: argv.watch,
|
incremental: argv.watch,
|
||||||
plugins: [
|
plugins: [
|
||||||
inlineWorker({
|
inlineWorker({
|
||||||
format: "cjs", platform: "browser",
|
...baseConfig,
|
||||||
|
format: "cjs",
|
||||||
target: 'es2022',
|
target: 'es2022',
|
||||||
bundle: true,
|
|
||||||
assetNames: "assets/[name]",
|
|
||||||
}),
|
}),
|
||||||
metaUrlPlugin()
|
metaUrlPlugin()
|
||||||
],
|
],
|
||||||
@ -98,8 +113,8 @@ const emitTypeScript = () => {
|
|||||||
"--",
|
"--",
|
||||||
"-m", "es2022",
|
"-m", "es2022",
|
||||||
"-outDir", outDirectory,
|
"-outDir", outDirectory,
|
||||||
|
"--declaration",
|
||||||
"--emitDeclarationOnly"
|
"--emitDeclarationOnly"
|
||||||
|
|
||||||
], {
|
], {
|
||||||
cwd: '.',
|
cwd: '.',
|
||||||
stdio: 'inherit',
|
stdio: 'inherit',
|
||||||
@ -107,36 +122,74 @@ const emitTypeScript = () => {
|
|||||||
|
|
||||||
if (child.status !== 0) {
|
if (child.status !== 0) {
|
||||||
console.error("Failed to execute tsc")
|
console.error("Failed to execute tsc")
|
||||||
process.exit(1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Do not continue if one step fails
|
||||||
const wasmPack = () => {
|
const wasmPack = () => {
|
||||||
let outDirectory = `${getLibDirectory()}/src/wasm-pack`;
|
let outDirectory = `${getLibDirectory()}/src/wasm`;
|
||||||
|
let profile = release ? "wasm-release" : "wasm-dev"
|
||||||
|
|
||||||
let child = spawnSync('npm', ["exec",
|
// language=toml
|
||||||
"wasm-pack","--",
|
let multithreaded_config = `target.wasm32-unknown-unknown.rustflags = [
|
||||||
|
# Enables features which are required for shared-memory
|
||||||
|
"-C", "target-feature=+atomics,+bulk-memory,+mutable-globals",
|
||||||
|
# Enables the possibility to import memory into wasm.
|
||||||
|
# Without --shared-memory it is not possible to use shared WebAssembly.Memory.
|
||||||
|
# Set maximum memory to 200MB
|
||||||
|
"-C", "link-args=--shared-memory --import-memory --max-memory=209715200"
|
||||||
|
]`
|
||||||
|
|
||||||
|
let cargo = spawnSync('cargo', [
|
||||||
|
...(multithreaded ? ["--config", multithreaded_config] : []),
|
||||||
"build",
|
"build",
|
||||||
"--out-name", "index",
|
"-p", "web", "--lib",
|
||||||
"--out-dir", outDirectory,
|
"--target", "wasm32-unknown-unknown",
|
||||||
getWebDirectory(),
|
"--profile", profile,
|
||||||
"--target", "web",
|
"--features", `${webgl ? "web-webgl," : ""}`,
|
||||||
"--",
|
...(multithreaded ? ["-Z", "build-std=std,panic_abort"] : []),
|
||||||
"--features", `${webgl ? "web-webgl" : ""}`,
|
|
||||||
"-Z", "build-std=std,panic_abort"
|
|
||||||
], {
|
], {
|
||||||
cwd: '.',
|
cwd: '.',
|
||||||
stdio: 'inherit',
|
stdio: 'inherit',
|
||||||
});
|
});
|
||||||
|
|
||||||
if (child.status !== 0) {
|
if (cargo.status !== 0) {
|
||||||
console.error("Failed to execute wasm-pack")
|
console.error("Failed to execute cargo build")
|
||||||
|
}
|
||||||
|
|
||||||
|
let wasmbindgen = spawnSync('wasm-bindgen', [
|
||||||
|
`${getProjectDirectory()}/target/wasm32-unknown-unknown/${profile}/web.wasm`,
|
||||||
|
"--out-name", "maplibre",
|
||||||
|
"--out-dir", outDirectory,
|
||||||
|
"--typescript",
|
||||||
|
"--target", "web",
|
||||||
|
"--debug",
|
||||||
|
], {
|
||||||
|
cwd: '.',
|
||||||
|
stdio: 'inherit',
|
||||||
|
});
|
||||||
|
|
||||||
|
if (wasmbindgen.status !== 0) {
|
||||||
|
console.error("Failed to execute wasm-bindgen")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (release) {
|
||||||
|
console.log("Running wasm-opt")
|
||||||
|
let wasmOpt = spawnSync('npm', ["exec",
|
||||||
|
"wasm-opt", "--",
|
||||||
|
`${outDirectory}/maplibre_bg.wasm`,
|
||||||
|
"-o", `${outDirectory}/maplibre_bg.wasm`,
|
||||||
|
"-O"
|
||||||
|
], {
|
||||||
|
cwd: '.',
|
||||||
|
stdio: 'inherit',
|
||||||
|
});
|
||||||
|
|
||||||
|
if (wasmOpt.status !== 0) {
|
||||||
|
console.error("Failed to execute wasm-opt")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Having package.json within another npm package is not supported. Remove that.
|
|
||||||
unlink(`${getLibDirectory()}/src/wasm-pack/package.json`, (err) => {
|
|
||||||
if (err) throw err;
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const watchResult = async (result) => {
|
const watchResult = async (result) => {
|
||||||
@ -149,17 +202,22 @@ const watchResult = async (result) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const update = async (path) => {
|
const update = async (path) => {
|
||||||
console.log(`Updating: ${path}`)
|
try {
|
||||||
if (path.endsWith(".rs")) {
|
console.log(`Updating: ${path}`)
|
||||||
console.log("Rebuilding Rust...")
|
if (path.endsWith(".rs")) {
|
||||||
wasmPack();
|
console.log("Rebuilding Rust...")
|
||||||
|
wasmPack();
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Rebuilding...")
|
||||||
|
await result.rebuild();
|
||||||
|
|
||||||
|
console.log("Emitting TypeScript types...")
|
||||||
|
emitTypeScript();
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Error while updating:")
|
||||||
|
console.error(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("Rebuilding...")
|
|
||||||
await result.rebuild();
|
|
||||||
|
|
||||||
console.log("Emitting TypeScript types...")
|
|
||||||
emitTypeScript();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("Watching...")
|
console.log("Watching...")
|
||||||
@ -171,7 +229,7 @@ const watchResult = async (result) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const esbuild = async (name, globalName = undefined) => {
|
const esbuild = async (name, globalName = undefined) => {
|
||||||
let result = await build({...baseSettings, format: name, globalName, outfile: `dist/esbuild-${name}/module.js`,});
|
let result = await build({...config, format: name, globalName, outfile: `dist/esbuild-${name}/module.js`,});
|
||||||
|
|
||||||
if (argv.watch) {
|
if (argv.watch) {
|
||||||
console.log("Watching is enabled.")
|
console.log("Watching is enabled.")
|
||||||
@ -180,7 +238,7 @@ const esbuild = async (name, globalName = undefined) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const start = async () => {
|
const start = async () => {
|
||||||
console.log("Running wasm-pack...")
|
console.log("Creating WASM...")
|
||||||
wasmPack();
|
wasmPack();
|
||||||
|
|
||||||
if (esm) {
|
if (esm) {
|
||||||
|
|||||||
454
web/lib/package-lock.json
generated
454
web/lib/package-lock.json
generated
@ -9,6 +9,7 @@
|
|||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"binaryen": "^110.0.0",
|
||||||
"spectorjs": "^0.9.27",
|
"spectorjs": "^0.9.27",
|
||||||
"wasm-feature-detect": "^1.2.11"
|
"wasm-feature-detect": "^1.2.11"
|
||||||
},
|
},
|
||||||
@ -18,7 +19,6 @@
|
|||||||
"esbuild": "^0.14.38",
|
"esbuild": "^0.14.38",
|
||||||
"esbuild-plugin-inline-worker": "^0.1.1",
|
"esbuild-plugin-inline-worker": "^0.1.1",
|
||||||
"typescript": "^4.5.4",
|
"typescript": "^4.5.4",
|
||||||
"wasm-pack": "^0.10.2",
|
|
||||||
"yargs": "^17.5.1"
|
"yargs": "^17.5.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -135,21 +135,6 @@
|
|||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/axios": {
|
|
||||||
"version": "0.21.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
|
|
||||||
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"follow-redirects": "^1.14.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/balanced-match": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
|
||||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/binary-extensions": {
|
"node_modules/binary-extensions": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||||
@ -159,28 +144,13 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/binary-install": {
|
"node_modules/binaryen": {
|
||||||
"version": "0.1.1",
|
"version": "110.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/binary-install/-/binary-install-0.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/binaryen/-/binaryen-110.0.0.tgz",
|
||||||
"integrity": "sha512-DqED0D/6LrS+BHDkKn34vhRqOGjy5gTMgvYZsGK2TpNbdPuz4h+MRlNgGv5QBRd7pWq/jylM4eKNCizgAq3kNQ==",
|
"integrity": "sha512-b1rQFvnjNIfuW0UYSBgwLIrKD9PaG0iEzWXyoWLBFp/HRdvgD+7LGUnxG+/yKz1+tyiTdRm/lFRxsmYXaULIUg==",
|
||||||
"dev": true,
|
"bin": {
|
||||||
"dependencies": {
|
"wasm-opt": "bin/wasm-opt",
|
||||||
"axios": "^0.21.1",
|
"wasm2js": "bin/wasm2js"
|
||||||
"rimraf": "^3.0.2",
|
|
||||||
"tar": "^6.1.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/brace-expansion": {
|
|
||||||
"version": "1.1.11",
|
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
|
||||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"balanced-match": "^1.0.0",
|
|
||||||
"concat-map": "0.0.1"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/braces": {
|
"node_modules/braces": {
|
||||||
@ -222,15 +192,6 @@
|
|||||||
"fsevents": "~2.3.2"
|
"fsevents": "~2.3.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/chownr": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
|
|
||||||
"integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
|
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/cliui": {
|
"node_modules/cliui": {
|
||||||
"version": "7.0.4",
|
"version": "7.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
|
||||||
@ -266,12 +227,6 @@
|
|||||||
"integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==",
|
"integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/concat-map": {
|
|
||||||
"version": "0.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
|
||||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/detect-libc": {
|
"node_modules/detect-libc": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
|
||||||
@ -707,44 +662,6 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/follow-redirects": {
|
|
||||||
"version": "1.15.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz",
|
|
||||||
"integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==",
|
|
||||||
"dev": true,
|
|
||||||
"funding": [
|
|
||||||
{
|
|
||||||
"type": "individual",
|
|
||||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=4.0"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"debug": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/fs-minipass": {
|
|
||||||
"version": "2.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
|
|
||||||
"integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"minipass": "^3.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/fs.realpath": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
|
||||||
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/fsevents": {
|
"node_modules/fsevents": {
|
||||||
"version": "2.3.2",
|
"version": "2.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||||
@ -768,26 +685,6 @@
|
|||||||
"node": "6.* || 8.* || >= 10.*"
|
"node": "6.* || 8.* || >= 10.*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/glob": {
|
|
||||||
"version": "7.2.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
|
||||||
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"fs.realpath": "^1.0.0",
|
|
||||||
"inflight": "^1.0.4",
|
|
||||||
"inherits": "2",
|
|
||||||
"minimatch": "^3.1.1",
|
|
||||||
"once": "^1.3.0",
|
|
||||||
"path-is-absolute": "^1.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "*"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/isaacs"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/glob-parent": {
|
"node_modules/glob-parent": {
|
||||||
"version": "5.1.2",
|
"version": "5.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||||
@ -800,22 +697,6 @@
|
|||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/inflight": {
|
|
||||||
"version": "1.0.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
|
||||||
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"once": "^1.3.0",
|
|
||||||
"wrappy": "1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/inherits": {
|
|
||||||
"version": "2.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
|
||||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/is-binary-path": {
|
"node_modules/is-binary-path": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||||
@ -894,55 +775,6 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/minimatch": {
|
|
||||||
"version": "3.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
|
||||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"brace-expansion": "^1.1.7"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/minipass": {
|
|
||||||
"version": "3.3.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.4.tgz",
|
|
||||||
"integrity": "sha512-I9WPbWHCGu8W+6k1ZiGpPu0GkoKBeorkfKNuAFBNS1HNFJvke82sxvI5bzcCNpWPorkOO5QQ+zomzzwRxejXiw==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"yallist": "^4.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/minizlib": {
|
|
||||||
"version": "2.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
|
|
||||||
"integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"minipass": "^3.0.0",
|
|
||||||
"yallist": "^4.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/mkdirp": {
|
|
||||||
"version": "1.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
|
||||||
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
|
|
||||||
"dev": true,
|
|
||||||
"bin": {
|
|
||||||
"mkdirp": "bin/cmd.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/normalize-path": {
|
"node_modules/normalize-path": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||||
@ -952,15 +784,6 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/once": {
|
|
||||||
"version": "1.4.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
|
||||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"wrappy": "1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/p-limit": {
|
"node_modules/p-limit": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
|
||||||
@ -1006,15 +829,6 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/path-is-absolute": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
|
||||||
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
|
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.10.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/picomatch": {
|
"node_modules/picomatch": {
|
||||||
"version": "2.3.1",
|
"version": "2.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||||
@ -1060,21 +874,6 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rimraf": {
|
|
||||||
"version": "3.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
|
||||||
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"glob": "^7.1.3"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"rimraf": "bin.js"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/isaacs"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/semver": {
|
"node_modules/semver": {
|
||||||
"version": "6.3.0",
|
"version": "6.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||||
@ -1115,23 +914,6 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tar": {
|
|
||||||
"version": "6.1.11",
|
|
||||||
"resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz",
|
|
||||||
"integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"chownr": "^2.0.0",
|
|
||||||
"fs-minipass": "^2.0.0",
|
|
||||||
"minipass": "^3.0.0",
|
|
||||||
"minizlib": "^2.1.1",
|
|
||||||
"mkdirp": "^1.0.3",
|
|
||||||
"yallist": "^4.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/to-regex-range": {
|
"node_modules/to-regex-range": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||||
@ -1162,19 +944,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.2.11.tgz",
|
"resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.2.11.tgz",
|
||||||
"integrity": "sha512-HUqwaodrQGaZgz1lZaNioIkog9tkeEJjrM3eq4aUL04whXOVDRc/o2EGb/8kV0QX411iAYWEqq7fMBmJ6dKS6w=="
|
"integrity": "sha512-HUqwaodrQGaZgz1lZaNioIkog9tkeEJjrM3eq4aUL04whXOVDRc/o2EGb/8kV0QX411iAYWEqq7fMBmJ6dKS6w=="
|
||||||
},
|
},
|
||||||
"node_modules/wasm-pack": {
|
|
||||||
"version": "0.10.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/wasm-pack/-/wasm-pack-0.10.3.tgz",
|
|
||||||
"integrity": "sha512-dg1PPyp+QwWrhfHsgG12K/y5xzwfaAoK1yuVC/DUAuQsDy5JywWDuA7Y/ionGwQz+JBZVw8jknaKBnaxaJfwTA==",
|
|
||||||
"dev": true,
|
|
||||||
"hasInstallScript": true,
|
|
||||||
"dependencies": {
|
|
||||||
"binary-install": "^0.1.0"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"wasm-pack": "run.js"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/wrap-ansi": {
|
"node_modules/wrap-ansi": {
|
||||||
"version": "7.0.0",
|
"version": "7.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||||
@ -1192,12 +961,6 @@
|
|||||||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/wrappy": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
|
||||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/y18n": {
|
"node_modules/y18n": {
|
||||||
"version": "5.0.8",
|
"version": "5.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||||
@ -1207,12 +970,6 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/yallist": {
|
|
||||||
"version": "4.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
|
||||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/yargs": {
|
"node_modules/yargs": {
|
||||||
"version": "17.5.1",
|
"version": "17.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz",
|
||||||
@ -1319,47 +1076,16 @@
|
|||||||
"picomatch": "^2.0.4"
|
"picomatch": "^2.0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"axios": {
|
|
||||||
"version": "0.21.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
|
|
||||||
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"follow-redirects": "^1.14.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"balanced-match": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
|
||||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"binary-extensions": {
|
"binary-extensions": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||||
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
|
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"binary-install": {
|
"binaryen": {
|
||||||
"version": "0.1.1",
|
"version": "110.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/binary-install/-/binary-install-0.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/binaryen/-/binaryen-110.0.0.tgz",
|
||||||
"integrity": "sha512-DqED0D/6LrS+BHDkKn34vhRqOGjy5gTMgvYZsGK2TpNbdPuz4h+MRlNgGv5QBRd7pWq/jylM4eKNCizgAq3kNQ==",
|
"integrity": "sha512-b1rQFvnjNIfuW0UYSBgwLIrKD9PaG0iEzWXyoWLBFp/HRdvgD+7LGUnxG+/yKz1+tyiTdRm/lFRxsmYXaULIUg=="
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"axios": "^0.21.1",
|
|
||||||
"rimraf": "^3.0.2",
|
|
||||||
"tar": "^6.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"brace-expansion": {
|
|
||||||
"version": "1.1.11",
|
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
|
||||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"balanced-match": "^1.0.0",
|
|
||||||
"concat-map": "0.0.1"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"braces": {
|
"braces": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
@ -1386,12 +1112,6 @@
|
|||||||
"readdirp": "~3.6.0"
|
"readdirp": "~3.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"chownr": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
|
|
||||||
"integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"cliui": {
|
"cliui": {
|
||||||
"version": "7.0.4",
|
"version": "7.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
|
||||||
@ -1424,12 +1144,6 @@
|
|||||||
"integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==",
|
"integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"concat-map": {
|
|
||||||
"version": "0.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
|
||||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"detect-libc": {
|
"detect-libc": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
|
||||||
@ -1657,27 +1371,6 @@
|
|||||||
"path-exists": "^4.0.0"
|
"path-exists": "^4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"follow-redirects": {
|
|
||||||
"version": "1.15.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz",
|
|
||||||
"integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"fs-minipass": {
|
|
||||||
"version": "2.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
|
|
||||||
"integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"minipass": "^3.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"fs.realpath": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
|
||||||
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"fsevents": {
|
"fsevents": {
|
||||||
"version": "2.3.2",
|
"version": "2.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||||
@ -1691,20 +1384,6 @@
|
|||||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"glob": {
|
|
||||||
"version": "7.2.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
|
||||||
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"fs.realpath": "^1.0.0",
|
|
||||||
"inflight": "^1.0.4",
|
|
||||||
"inherits": "2",
|
|
||||||
"minimatch": "^3.1.1",
|
|
||||||
"once": "^1.3.0",
|
|
||||||
"path-is-absolute": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"glob-parent": {
|
"glob-parent": {
|
||||||
"version": "5.1.2",
|
"version": "5.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||||
@ -1714,22 +1393,6 @@
|
|||||||
"is-glob": "^4.0.1"
|
"is-glob": "^4.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"inflight": {
|
|
||||||
"version": "1.0.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
|
||||||
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"once": "^1.3.0",
|
|
||||||
"wrappy": "1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"inherits": {
|
|
||||||
"version": "2.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
|
||||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"is-binary-path": {
|
"is-binary-path": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||||
@ -1784,55 +1447,12 @@
|
|||||||
"semver": "^6.0.0"
|
"semver": "^6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"minimatch": {
|
|
||||||
"version": "3.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
|
||||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"brace-expansion": "^1.1.7"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"minipass": {
|
|
||||||
"version": "3.3.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.4.tgz",
|
|
||||||
"integrity": "sha512-I9WPbWHCGu8W+6k1ZiGpPu0GkoKBeorkfKNuAFBNS1HNFJvke82sxvI5bzcCNpWPorkOO5QQ+zomzzwRxejXiw==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"yallist": "^4.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"minizlib": {
|
|
||||||
"version": "2.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
|
|
||||||
"integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"minipass": "^3.0.0",
|
|
||||||
"yallist": "^4.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"mkdirp": {
|
|
||||||
"version": "1.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
|
||||||
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"normalize-path": {
|
"normalize-path": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||||
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
|
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"once": {
|
|
||||||
"version": "1.4.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
|
||||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"wrappy": "1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"p-limit": {
|
"p-limit": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
|
||||||
@ -1863,12 +1483,6 @@
|
|||||||
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
|
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"path-is-absolute": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
|
||||||
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"picomatch": {
|
"picomatch": {
|
||||||
"version": "2.3.1",
|
"version": "2.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||||
@ -1899,15 +1513,6 @@
|
|||||||
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
|
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"rimraf": {
|
|
||||||
"version": "3.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
|
||||||
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"glob": "^7.1.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"semver": {
|
"semver": {
|
||||||
"version": "6.3.0",
|
"version": "6.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||||
@ -1939,20 +1544,6 @@
|
|||||||
"ansi-regex": "^5.0.1"
|
"ansi-regex": "^5.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tar": {
|
|
||||||
"version": "6.1.11",
|
|
||||||
"resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz",
|
|
||||||
"integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"chownr": "^2.0.0",
|
|
||||||
"fs-minipass": "^2.0.0",
|
|
||||||
"minipass": "^3.0.0",
|
|
||||||
"minizlib": "^2.1.1",
|
|
||||||
"mkdirp": "^1.0.3",
|
|
||||||
"yallist": "^4.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"to-regex-range": {
|
"to-regex-range": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||||
@ -1973,15 +1564,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.2.11.tgz",
|
"resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.2.11.tgz",
|
||||||
"integrity": "sha512-HUqwaodrQGaZgz1lZaNioIkog9tkeEJjrM3eq4aUL04whXOVDRc/o2EGb/8kV0QX411iAYWEqq7fMBmJ6dKS6w=="
|
"integrity": "sha512-HUqwaodrQGaZgz1lZaNioIkog9tkeEJjrM3eq4aUL04whXOVDRc/o2EGb/8kV0QX411iAYWEqq7fMBmJ6dKS6w=="
|
||||||
},
|
},
|
||||||
"wasm-pack": {
|
|
||||||
"version": "0.10.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/wasm-pack/-/wasm-pack-0.10.3.tgz",
|
|
||||||
"integrity": "sha512-dg1PPyp+QwWrhfHsgG12K/y5xzwfaAoK1yuVC/DUAuQsDy5JywWDuA7Y/ionGwQz+JBZVw8jknaKBnaxaJfwTA==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"binary-install": "^0.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"wrap-ansi": {
|
"wrap-ansi": {
|
||||||
"version": "7.0.0",
|
"version": "7.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||||
@ -1993,24 +1575,12 @@
|
|||||||
"strip-ansi": "^6.0.0"
|
"strip-ansi": "^6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"wrappy": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
|
||||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"y18n": {
|
"y18n": {
|
||||||
"version": "5.0.8",
|
"version": "5.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||||
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
|
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"yallist": {
|
|
||||||
"version": "4.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
|
||||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"yargs": {
|
"yargs": {
|
||||||
"version": "17.5.1",
|
"version": "17.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz",
|
||||||
|
|||||||
@ -16,16 +16,16 @@
|
|||||||
"main": "dist/esbuild-cjs/main.js",
|
"main": "dist/esbuild-cjs/main.js",
|
||||||
"types": "dist/ts/index.d.ts",
|
"types": "dist/ts/index.d.ts",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"binaryen": "^110.0.0",
|
||||||
"spectorjs": "^0.9.27",
|
"spectorjs": "^0.9.27",
|
||||||
"wasm-feature-detect": "^1.2.11"
|
"wasm-feature-detect": "^1.2.11"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"chokidar": "^3.5.3",
|
|
||||||
"@chialab/esbuild-plugin-meta-url": "^0.15.28",
|
"@chialab/esbuild-plugin-meta-url": "^0.15.28",
|
||||||
|
"chokidar": "^3.5.3",
|
||||||
"esbuild": "^0.14.38",
|
"esbuild": "^0.14.38",
|
||||||
"esbuild-plugin-inline-worker": "^0.1.1",
|
"esbuild-plugin-inline-worker": "^0.1.1",
|
||||||
"typescript": "^4.5.4",
|
"typescript": "^4.5.4",
|
||||||
"wasm-pack": "^0.10.2",
|
|
||||||
"yargs": "^17.5.1"
|
"yargs": "^17.5.1"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|||||||
73
web/lib/src/browser.ts
Normal file
73
web/lib/src/browser.ts
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
import {
|
||||||
|
bigInt,
|
||||||
|
bulkMemory,
|
||||||
|
exceptions,
|
||||||
|
multiValue,
|
||||||
|
mutableGlobals,
|
||||||
|
referenceTypes,
|
||||||
|
saturatedFloatToInt,
|
||||||
|
signExtensions,
|
||||||
|
simd,
|
||||||
|
tailCall,
|
||||||
|
threads
|
||||||
|
} from "wasm-feature-detect"
|
||||||
|
|
||||||
|
|
||||||
|
export const checkRequirements = () => {
|
||||||
|
if (MULTITHREADED) {
|
||||||
|
if (!isSecureContext) {
|
||||||
|
return "isSecureContext is false!"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!crossOriginIsolated) {
|
||||||
|
return "crossOriginIsolated is false! " +
|
||||||
|
"The Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy HTTP headers are required."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WEBGL) {
|
||||||
|
if (!isWebGLSupported()) {
|
||||||
|
return "WebGL is not supported in this Browser!"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!("gpu" in navigator)) {
|
||||||
|
return "WebGPU is not supported in this Browser!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
export const isWebGLSupported = () => {
|
||||||
|
try {
|
||||||
|
const canvas = document.createElement('canvas')
|
||||||
|
canvas.getContext("webgl")
|
||||||
|
return true
|
||||||
|
} catch (x) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const checkWasmFeatures = async () => {
|
||||||
|
const checkFeature = async function (featureName: string, feature: () => Promise<boolean>) {
|
||||||
|
let result = await feature();
|
||||||
|
let msg = `The feature ${featureName} returned: ${result}`;
|
||||||
|
if (result) {
|
||||||
|
console.log(msg);
|
||||||
|
} else {
|
||||||
|
console.warn(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await checkFeature("bulkMemory", bulkMemory);
|
||||||
|
await checkFeature("exceptions", exceptions);
|
||||||
|
await checkFeature("multiValue", multiValue);
|
||||||
|
await checkFeature("mutableGlobals", mutableGlobals);
|
||||||
|
await checkFeature("referenceTypes", referenceTypes);
|
||||||
|
await checkFeature("saturatedFloatToInt", saturatedFloatToInt);
|
||||||
|
await checkFeature("signExtensions", signExtensions);
|
||||||
|
await checkFeature("simd", simd);
|
||||||
|
await checkFeature("tailCall", tailCall);
|
||||||
|
await checkFeature("threads", threads);
|
||||||
|
await checkFeature("bigInt", bigInt);
|
||||||
|
}
|
||||||
6
web/lib/src/canvas.ts
Normal file
6
web/lib/src/canvas.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export const preventDefaultTouchActions = () => {
|
||||||
|
document.body.querySelectorAll("canvas").forEach(canvas => {
|
||||||
|
canvas.addEventListener("touchstart", e => e.preventDefault())
|
||||||
|
canvas.addEventListener("touchmove", e => e.preventDefault())
|
||||||
|
})
|
||||||
|
}
|
||||||
@ -1,148 +1,69 @@
|
|||||||
import init, {create_pool_scheduler, run} from "./wasm-pack"
|
import * as maplibre from "./wasm/maplibre"
|
||||||
import {Spector} from "spectorjs"
|
import {Spector} from "spectorjs"
|
||||||
import {WebWorkerMessageType} from "./types"
|
import {checkRequirements, checkWasmFeatures} from "./browser";
|
||||||
import {
|
import {preventDefaultTouchActions} from "./canvas";
|
||||||
bigInt,
|
// @ts-ignore esbuild plugin is handling this
|
||||||
bulkMemory,
|
import MultithreadedPoolWorker from './multithreaded/multithreaded-pool.worker.js';
|
||||||
exceptions,
|
// @ts-ignore esbuild plugin is handling this
|
||||||
multiValue,
|
import PoolWorker from './singlethreaded/pool.worker.js';
|
||||||
mutableGlobals,
|
|
||||||
referenceTypes,
|
|
||||||
saturatedFloatToInt,
|
|
||||||
signExtensions,
|
|
||||||
simd,
|
|
||||||
tailCall,
|
|
||||||
threads
|
|
||||||
} from "wasm-feature-detect"
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
import PoolWorker from './pool.worker.js';
|
|
||||||
|
|
||||||
const isWebGLSupported = () => {
|
|
||||||
try {
|
|
||||||
const canvas = document.createElement('canvas')
|
|
||||||
canvas.getContext("webgl")
|
|
||||||
return true
|
|
||||||
} catch (x) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const checkWasmFeatures = async () => {
|
|
||||||
const checkFeature = async function (featureName: string, feature: () => Promise<boolean>) {
|
|
||||||
let result = await feature();
|
|
||||||
let msg = `The feature ${featureName} returned: ${result}`;
|
|
||||||
if (result) {
|
|
||||||
console.log(msg);
|
|
||||||
} else {
|
|
||||||
console.warn(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await checkFeature("bulkMemory", bulkMemory);
|
|
||||||
await checkFeature("exceptions", exceptions);
|
|
||||||
await checkFeature("multiValue", multiValue);
|
|
||||||
await checkFeature("mutableGlobals", mutableGlobals);
|
|
||||||
await checkFeature("referenceTypes", referenceTypes);
|
|
||||||
await checkFeature("saturatedFloatToInt", saturatedFloatToInt);
|
|
||||||
await checkFeature("signExtensions", signExtensions);
|
|
||||||
await checkFeature("simd", simd);
|
|
||||||
await checkFeature("tailCall", tailCall);
|
|
||||||
await checkFeature("threads", threads);
|
|
||||||
await checkFeature("bigInt", bigInt);
|
|
||||||
}
|
|
||||||
|
|
||||||
const alertUser = (message: string) => {
|
|
||||||
console.error(message)
|
|
||||||
alert(message)
|
|
||||||
}
|
|
||||||
|
|
||||||
const checkRequirements = () => {
|
|
||||||
if (!isSecureContext) {
|
|
||||||
alertUser("isSecureContext is false!")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!crossOriginIsolated) {
|
|
||||||
alertUser("crossOriginIsolated is false! " +
|
|
||||||
"The Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy HTTP headers are required.")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (WEBGL) {
|
|
||||||
if (!isWebGLSupported()) {
|
|
||||||
alertUser("WebGL is not supported in this Browser!")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
let spector = new Spector()
|
|
||||||
spector.displayUI()
|
|
||||||
} else {
|
|
||||||
if (!("gpu" in navigator)) {
|
|
||||||
let message = "WebGPU is not supported in this Browser!"
|
|
||||||
alertUser(message)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
const preventDefaultTouchActions = () => {
|
|
||||||
document.body.querySelectorAll("canvas").forEach(canvas => {
|
|
||||||
canvas.addEventListener("touchstart", e => e.preventDefault())
|
|
||||||
canvas.addEventListener("touchmove", e => e.preventDefault())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
let WORKER_COUNT = 4
|
|
||||||
const createWorker = (id: number, memory: WebAssembly.Memory) => {
|
|
||||||
const worker = new Worker(new URL('./legacy.worker.ts', import.meta.url), {
|
|
||||||
type: "module",
|
|
||||||
})
|
|
||||||
worker.postMessage({type: "init", memory} as WebWorkerMessageType)
|
|
||||||
|
|
||||||
return worker
|
|
||||||
}
|
|
||||||
|
|
||||||
const setupLegacyWebWorker = (schedulerPtr: number, memory: WebAssembly.Memory) => {
|
|
||||||
let workers: [number, Worker][] = Array.from(
|
|
||||||
new Array(WORKER_COUNT).keys(),
|
|
||||||
(id) => [new_thread_local_state(schedulerPtr), createWorker(id, memory)]
|
|
||||||
)
|
|
||||||
|
|
||||||
window.schedule_tile_request = (url: string, request_id: number) => {
|
|
||||||
const [state, worker] = workers[Math.floor(Math.random() * workers.length)]
|
|
||||||
worker.postMessage({
|
|
||||||
type: "fetch_tile",
|
|
||||||
threadLocalState: state,
|
|
||||||
url,
|
|
||||||
request_id
|
|
||||||
} as WebWorkerMessageType)
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
export const startMapLibre = async (wasmPath: string | undefined, workerPath: string | undefined) => {
|
export const startMapLibre = async (wasmPath: string | undefined, workerPath: string | undefined) => {
|
||||||
await checkWasmFeatures()
|
await checkWasmFeatures()
|
||||||
|
|
||||||
if (!checkRequirements()) {
|
let message = checkRequirements();
|
||||||
|
if (message) {
|
||||||
|
console.error(message)
|
||||||
|
alert(message)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (WEBGL) {
|
||||||
|
let spector = new Spector()
|
||||||
|
spector.displayUI()
|
||||||
|
}
|
||||||
|
|
||||||
preventDefaultTouchActions();
|
preventDefaultTouchActions();
|
||||||
|
|
||||||
let MEMORY_PAGES = 16 * 1024
|
if (MULTITHREADED) {
|
||||||
|
const MEMORY = 209715200; // 200MB
|
||||||
|
const PAGES = 64 * 1024;
|
||||||
|
|
||||||
const memory = new WebAssembly.Memory({initial: 1024, maximum: MEMORY_PAGES, shared: true})
|
const memory = new WebAssembly.Memory({initial: 1024, maximum: MEMORY / PAGES, shared: true})
|
||||||
await init(wasmPath, memory)
|
await maplibre.default(wasmPath, memory)
|
||||||
|
|
||||||
const schedulerPtr = create_pool_scheduler(() => {
|
maplibre.run(await maplibre.create_map(() => {
|
||||||
return workerPath ? new PoolWorker(workerPath, {
|
return workerPath ? new Worker(workerPath, {
|
||||||
type: 'module'
|
type: 'module'
|
||||||
}) : PoolWorker();
|
}) : MultithreadedPoolWorker();
|
||||||
})
|
}))
|
||||||
|
} else {
|
||||||
|
const memory = new WebAssembly.Memory({initial: 1024, shared: false})
|
||||||
|
await maplibre.default(wasmPath, memory);
|
||||||
|
|
||||||
// setupLegacyWebWorker(schedulerPtr, memory)
|
let callbacks: {worker_callback?: (message: MessageEvent) => void} = {}
|
||||||
|
|
||||||
await run(schedulerPtr)
|
let map = await maplibre.create_map(() => {
|
||||||
|
let worker: Worker = workerPath ? new Worker(workerPath, {
|
||||||
|
type: 'module'
|
||||||
|
}) : PoolWorker();
|
||||||
|
|
||||||
|
worker.onmessage = (message: MessageEvent) => {
|
||||||
|
callbacks.worker_callback(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
return worker;
|
||||||
|
})
|
||||||
|
|
||||||
|
let clonedMap = maplibre.clone_map(map)
|
||||||
|
|
||||||
|
callbacks.worker_callback = (message) => {
|
||||||
|
let tag = message.data[0];
|
||||||
|
let data = new Uint8Array(message.data[1]);
|
||||||
|
|
||||||
|
// @ts-ignore TODO unsync_main_entry may not be defined
|
||||||
|
maplibre.singlethreaded_main_entry(clonedMap, tag, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
maplibre.run(map)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,32 +0,0 @@
|
|||||||
/*import init, {InitOutput, tessellate_layers} from "./wasm-pack"
|
|
||||||
import {WebWorkerMessageType} from "./types"
|
|
||||||
|
|
||||||
let module: Promise<InitOutput> = null
|
|
||||||
|
|
||||||
onmessage = async message => {
|
|
||||||
let messageData: WebWorkerMessageType = message.data
|
|
||||||
console.dir(messageData)
|
|
||||||
|
|
||||||
switch (messageData.type) {
|
|
||||||
case "init":
|
|
||||||
if (module != null) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
module = init(undefined, messageData.memory)
|
|
||||||
break
|
|
||||||
case "fetch_tile":
|
|
||||||
let {threadLocalState, url, request_id} = messageData
|
|
||||||
await module
|
|
||||||
|
|
||||||
console.log("Fetching from " + self.name)
|
|
||||||
|
|
||||||
let result = await fetch(url)
|
|
||||||
let buffer = await result.arrayBuffer()
|
|
||||||
|
|
||||||
tessellate_layers(threadLocalState, request_id, new Uint8Array(buffer))
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
console.warn("WebWorker received unknown message!")
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import init, {child_entry_point} from "./wasm-pack"
|
import * as maplibre from "../wasm/maplibre"
|
||||||
|
|
||||||
onmessage = async message => {
|
onmessage = async message => {
|
||||||
const initialised = init(message.data[0], message.data[1]).catch(err => {
|
const initialised = maplibre.default(message.data[0], message.data[1]).catch(err => {
|
||||||
// Propagate to main `onerror`:
|
// Propagate to main `onerror`:
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
throw err;
|
throw err;
|
||||||
@ -13,6 +13,7 @@ onmessage = async message => {
|
|||||||
self.onmessage = async message => {
|
self.onmessage = async message => {
|
||||||
// This will queue further commands up until the module is fully initialised:
|
// This will queue further commands up until the module is fully initialised:
|
||||||
await initialised;
|
await initialised;
|
||||||
child_entry_point(message.data);
|
// @ts-ignore TODO may not exist
|
||||||
|
await maplibre.multithreaded_worker_entry(message.data);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -1,17 +0,0 @@
|
|||||||
/*
|
|
||||||
import {registerRoute} from 'workbox-routing';
|
|
||||||
import {CacheFirst} from 'workbox-strategies';
|
|
||||||
import {CacheableResponsePlugin} from 'workbox-cacheable-response';
|
|
||||||
|
|
||||||
registerRoute(
|
|
||||||
({url}) => url.pathname.endsWith('pbf'),
|
|
||||||
new CacheFirst({
|
|
||||||
cacheName: 'pbf-cache',
|
|
||||||
plugins: [
|
|
||||||
new CacheableResponsePlugin({
|
|
||||||
statuses: [0, 200],
|
|
||||||
})
|
|
||||||
]
|
|
||||||
})
|
|
||||||
);
|
|
||||||
*/
|
|
||||||
23
web/lib/src/singlethreaded/pool.worker.ts
Normal file
23
web/lib/src/singlethreaded/pool.worker.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import * as maplibre from "../wasm/maplibre"
|
||||||
|
|
||||||
|
onmessage = async message => {
|
||||||
|
const memory = new WebAssembly.Memory({initial: 1024, shared: false})
|
||||||
|
let module = message.data[0];
|
||||||
|
const initialised = maplibre.default(module, memory).catch(err => {
|
||||||
|
// Propagate to main `onerror`:
|
||||||
|
setTimeout(() => {
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
// Rethrow to keep promise rejected and prevent execution of further commands:
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
|
||||||
|
self.onmessage = async message => {
|
||||||
|
// This will queue further commands up until the module is fully initialised:
|
||||||
|
await initialised;
|
||||||
|
let procedure_ptr = message.data[0];
|
||||||
|
let input = message.data[1];
|
||||||
|
// @ts-ignore TODO
|
||||||
|
await maplibre.singlethreaded_worker_entry(procedure_ptr, input);
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -1,9 +0,0 @@
|
|||||||
export type WebWorkerMessageType = {
|
|
||||||
type: 'init',
|
|
||||||
memory: WebAssembly.Memory
|
|
||||||
} | {
|
|
||||||
type: 'fetch_tile',
|
|
||||||
threadLocalState: number,
|
|
||||||
url: string,
|
|
||||||
request_id: number,
|
|
||||||
}
|
|
||||||
@ -14,4 +14,4 @@
|
|||||||
"typeRoots": ["@types"]
|
"typeRoots": ["@types"]
|
||||||
},
|
},
|
||||||
"include": ["./src/**/*"]
|
"include": ["./src/**/*"]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,7 @@ pub struct WebError(pub String);
|
|||||||
impl From<JsValue> for WebError {
|
impl From<JsValue> for WebError {
|
||||||
fn from(maybe_error: JsValue) -> Self {
|
fn from(maybe_error: JsValue) -> Self {
|
||||||
assert!(maybe_error.is_instance_of::<JSError>());
|
assert!(maybe_error.is_instance_of::<JSError>());
|
||||||
let error: JSError = maybe_error.dyn_into().unwrap();
|
let error: JSError = maybe_error.dyn_into().unwrap(); // TODO: Remove unwrap
|
||||||
WebError(error.message().as_string().unwrap())
|
WebError(error.message().as_string().unwrap()) // TODO: remove unwrap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
use std::panic;
|
#![feature(allocator_api, new_uninit)]
|
||||||
|
|
||||||
use maplibre::{io::scheduler::Scheduler, MapBuilder};
|
use std::{borrow::BorrowMut, cell::RefCell, mem, ops::Deref, panic, rc::Rc};
|
||||||
use maplibre_winit::winit::WinitMapWindowConfig;
|
|
||||||
|
use maplibre::{io::scheduler::NopScheduler, Map, MapBuilder};
|
||||||
|
use maplibre_winit::winit::{WinitEnvironment, WinitMapWindowConfig};
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
use crate::platform::{
|
use crate::platform::http_client::WHATWGFetchHttpClient;
|
||||||
http_client::WHATWGFetchHttpClient, schedule_method::WebWorkerPoolScheduleMethod,
|
|
||||||
};
|
|
||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
mod platform;
|
mod platform;
|
||||||
@ -38,31 +38,76 @@ pub fn wasm_bindgen_start() {
|
|||||||
enable_tracing();
|
enable_tracing();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[cfg(not(target_feature = "atomics"))]
|
||||||
pub fn create_pool_scheduler(
|
pub type MapType = Map<
|
||||||
new_worker: js_sys::Function,
|
WinitEnvironment<
|
||||||
) -> *mut Scheduler<WebWorkerPoolScheduleMethod> {
|
NopScheduler,
|
||||||
let scheduler = Box::new(Scheduler::new(WebWorkerPoolScheduleMethod::new(new_worker)));
|
WHATWGFetchHttpClient,
|
||||||
|
platform::singlethreaded::transferables::LinearTransferables,
|
||||||
|
platform::singlethreaded::apc::PassingAsyncProcedureCall,
|
||||||
|
>,
|
||||||
|
>;
|
||||||
|
|
||||||
Box::into_raw(scheduler)
|
#[cfg(target_feature = "atomics")]
|
||||||
|
pub type MapType = Map<
|
||||||
|
WinitEnvironment<
|
||||||
|
platform::multithreaded::pool_scheduler::WebWorkerPoolScheduler,
|
||||||
|
WHATWGFetchHttpClient,
|
||||||
|
maplibre::io::transferables::DefaultTransferables,
|
||||||
|
maplibre::io::apc::SchedulerAsyncProcedureCall<
|
||||||
|
WHATWGFetchHttpClient,
|
||||||
|
platform::multithreaded::pool_scheduler::WebWorkerPoolScheduler,
|
||||||
|
>,
|
||||||
|
>,
|
||||||
|
>;
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub async fn create_map(new_worker: js_sys::Function) -> u32 {
|
||||||
|
// Either call forget or the main loop to keep worker loop alive
|
||||||
|
let mut builder = MapBuilder::new()
|
||||||
|
.with_map_window_config(WinitMapWindowConfig::new("maplibre".to_string()))
|
||||||
|
.with_http_client(WHATWGFetchHttpClient::new());
|
||||||
|
|
||||||
|
#[cfg(target_feature = "atomics")]
|
||||||
|
{
|
||||||
|
builder = builder
|
||||||
|
.with_apc(maplibre::io::apc::SchedulerAsyncProcedureCall::new(
|
||||||
|
WHATWGFetchHttpClient::new(),
|
||||||
|
platform::multithreaded::pool_scheduler::WebWorkerPoolScheduler::new(
|
||||||
|
new_worker.clone(),
|
||||||
|
),
|
||||||
|
))
|
||||||
|
.with_scheduler(
|
||||||
|
platform::multithreaded::pool_scheduler::WebWorkerPoolScheduler::new(new_worker),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_feature = "atomics"))]
|
||||||
|
{
|
||||||
|
builder = builder
|
||||||
|
.with_apc(platform::singlethreaded::apc::PassingAsyncProcedureCall::new(new_worker, 4))
|
||||||
|
.with_scheduler(NopScheduler);
|
||||||
|
}
|
||||||
|
|
||||||
|
let map: MapType = builder.build().initialize().await;
|
||||||
|
|
||||||
|
Rc::into_raw(Rc::new(RefCell::new(map))) as u32
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub async fn run(scheduler_ptr: *mut Scheduler<WebWorkerPoolScheduleMethod>) {
|
pub unsafe fn clone_map(map_ptr: *const RefCell<MapType>) -> *const RefCell<MapType> {
|
||||||
let scheduler: Box<Scheduler<WebWorkerPoolScheduleMethod>> =
|
let mut map = Rc::from_raw(map_ptr);
|
||||||
unsafe { Box::from_raw(scheduler_ptr) };
|
let rc = map.clone();
|
||||||
|
let cloned = Rc::into_raw(rc);
|
||||||
|
mem::forget(map);
|
||||||
|
cloned
|
||||||
|
}
|
||||||
|
|
||||||
// Either call forget or the main loop to keep worker loop alive
|
#[wasm_bindgen]
|
||||||
MapBuilder::new()
|
pub unsafe fn run(map_ptr: *const RefCell<MapType>) {
|
||||||
.with_map_window_config(WinitMapWindowConfig::new("maplibre".to_string()))
|
let mut map = Rc::from_raw(map_ptr);
|
||||||
.with_http_client(WHATWGFetchHttpClient::new())
|
|
||||||
.with_existing_scheduler(*scheduler)
|
|
||||||
.build()
|
|
||||||
.initialize()
|
|
||||||
.await
|
|
||||||
.run();
|
|
||||||
|
|
||||||
// std::mem::forget(scheduler);
|
map.deref().borrow().run();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@ -23,12 +23,12 @@ impl WHATWGFetchHttpClient {
|
|||||||
// Get the global scope
|
// Get the global scope
|
||||||
let global = js_sys::global();
|
let global = js_sys::global();
|
||||||
assert!(global.is_instance_of::<WorkerGlobalScope>());
|
assert!(global.is_instance_of::<WorkerGlobalScope>());
|
||||||
let scope = global.dyn_into::<WorkerGlobalScope>().unwrap();
|
let scope = global.dyn_into::<WorkerGlobalScope>().unwrap(); // TODO: remove unwrap
|
||||||
|
|
||||||
// Call fetch on global scope
|
// Call fetch on global scope
|
||||||
let maybe_response = JsFuture::from(scope.fetch_with_request(&request)).await?;
|
let maybe_response = JsFuture::from(scope.fetch_with_request(&request)).await?;
|
||||||
assert!(maybe_response.is_instance_of::<Response>());
|
assert!(maybe_response.is_instance_of::<Response>());
|
||||||
let response: Response = maybe_response.dyn_into().unwrap();
|
let response: Response = maybe_response.dyn_into().unwrap(); // TODO: remove unwrap
|
||||||
|
|
||||||
// Get ArrayBuffer
|
// Get ArrayBuffer
|
||||||
let maybe_array_buffer = JsFuture::from(response.array_buffer()?).await?;
|
let maybe_array_buffer = JsFuture::from(response.array_buffer()?).await?;
|
||||||
@ -39,7 +39,7 @@ impl WHATWGFetchHttpClient {
|
|||||||
let maybe_array_buffer = Self::fetch_array_buffer(url).await?;
|
let maybe_array_buffer = Self::fetch_array_buffer(url).await?;
|
||||||
|
|
||||||
assert!(maybe_array_buffer.is_instance_of::<ArrayBuffer>());
|
assert!(maybe_array_buffer.is_instance_of::<ArrayBuffer>());
|
||||||
let array_buffer: ArrayBuffer = maybe_array_buffer.dyn_into().unwrap();
|
let array_buffer: ArrayBuffer = maybe_array_buffer.dyn_into().unwrap(); // TODO: remove unwrap
|
||||||
|
|
||||||
// Copy data to Vec<u8>
|
// Copy data to Vec<u8>
|
||||||
let buffer: Uint8Array = Uint8Array::new(&array_buffer);
|
let buffer: Uint8Array = Uint8Array::new(&array_buffer);
|
||||||
|
|||||||
@ -1,52 +0,0 @@
|
|||||||
use maplibre::{
|
|
||||||
coords::TileCoords,
|
|
||||||
io::{scheduler::Scheduler, TileRequestID},
|
|
||||||
stages::SharedThreadState,
|
|
||||||
};
|
|
||||||
use wasm_bindgen::prelude::*;
|
|
||||||
|
|
||||||
use super::schedule_method::WebWorkerPoolScheduleMethod;
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
extern "C" {
|
|
||||||
fn schedule_tile_request(url: &str, request_id: u32);
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME
|
|
||||||
/*#[wasm_bindgen]
|
|
||||||
pub fn new_thread_local_state(scheduler_ptr: *mut Scheduler) -> *mut SharedThreadState {
|
|
||||||
let scheduler: Box<Scheduler> = unsafe { Box::from_raw(scheduler_ptr) };
|
|
||||||
let state = Box::new(scheduler.new_thread_local_state());
|
|
||||||
let state_ptr = Box::into_raw(state);
|
|
||||||
// Call forget such that scheduler does not get deallocated
|
|
||||||
std::mem::forget(scheduler);
|
|
||||||
return state_ptr;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
pub fn new_thread_local_state(_scheduler_ptr: *mut Scheduler<WebWorkerPoolScheduleMethod>) -> u32 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
pub fn tessellate_layers(state_ptr: *mut SharedThreadState, request_id: u32, data: Box<[u8]>) {
|
|
||||||
let state: Box<SharedThreadState> = unsafe { Box::from_raw(state_ptr) };
|
|
||||||
|
|
||||||
state.process_tile(request_id, data).unwrap();
|
|
||||||
|
|
||||||
// Call forget such that scheduler does not get deallocated
|
|
||||||
std::mem::forget(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn request_tile(request_id: TileRequestID, coords: TileCoords) {
|
|
||||||
schedule_tile_request(
|
|
||||||
format!(
|
|
||||||
"https://maps.tuerantuer.org/europe_germany/{z}/{x}/{y}.pbf",
|
|
||||||
x = coords.x,
|
|
||||||
y = coords.y,
|
|
||||||
z = coords.z,
|
|
||||||
)
|
|
||||||
.as_str(),
|
|
||||||
request_id,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@ -1,3 +1,10 @@
|
|||||||
|
use std::future::Future;
|
||||||
|
|
||||||
|
use maplibre::error::Error;
|
||||||
pub mod http_client;
|
pub mod http_client;
|
||||||
pub mod pool;
|
|
||||||
pub mod schedule_method;
|
#[cfg(target_feature = "atomics")]
|
||||||
|
pub mod multithreaded;
|
||||||
|
|
||||||
|
#[cfg(not(target_feature = "atomics"))]
|
||||||
|
pub mod singlethreaded;
|
||||||
|
|||||||
2
web/src/platform/multithreaded/mod.rs
Normal file
2
web/src/platform/multithreaded/mod.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
pub mod pool;
|
||||||
|
pub mod pool_scheduler;
|
||||||
@ -2,7 +2,7 @@
|
|||||||
//! web workers which can be used to execute work.
|
//! web workers which can be used to execute work.
|
||||||
//! Adopted from [wasm-bindgen example](https://github.com/rustwasm/wasm-bindgen/blob/0eba2efe45801b71f8873bc368c58a8ed8e894ff/examples/raytrace-parallel/src/pool.rs)
|
//! Adopted from [wasm-bindgen example](https://github.com/rustwasm/wasm-bindgen/blob/0eba2efe45801b71f8873bc368c58a8ed8e894ff/examples/raytrace-parallel/src/pool.rs)
|
||||||
|
|
||||||
use std::{cell::RefCell, rc::Rc};
|
use std::{borrow::BorrowMut, cell::RefCell, future::Future, rc::Rc};
|
||||||
|
|
||||||
use js_sys::Promise;
|
use js_sys::Promise;
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
@ -23,7 +23,6 @@ pub struct WorkerPool {
|
|||||||
|
|
||||||
struct PoolState {
|
struct PoolState {
|
||||||
workers: RefCell<Vec<Worker>>,
|
workers: RefCell<Vec<Worker>>,
|
||||||
callback: Closure<dyn FnMut(Event)>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Work {
|
struct Work {
|
||||||
@ -46,9 +45,6 @@ impl WorkerPool {
|
|||||||
new_worker,
|
new_worker,
|
||||||
state: Rc::new(PoolState {
|
state: Rc::new(PoolState {
|
||||||
workers: RefCell::new(Vec::with_capacity(initial)),
|
workers: RefCell::new(Vec::with_capacity(initial)),
|
||||||
callback: Closure::wrap(Box::new(|event: Event| {
|
|
||||||
log::error!("unhandled event: {}", event.type_());
|
|
||||||
}) as Box<dyn FnMut(Event)>),
|
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
for _ in 0..initial {
|
for _ in 0..initial {
|
||||||
@ -95,13 +91,13 @@ impl WorkerPool {
|
|||||||
/// message is sent to it.
|
/// message is sent to it.
|
||||||
fn worker(&self) -> Result<Worker, JsValue> {
|
fn worker(&self) -> Result<Worker, JsValue> {
|
||||||
let workers = self.state.workers.borrow();
|
let workers = self.state.workers.borrow();
|
||||||
let result = match workers.choose(&mut rand::thread_rng()) {
|
let result = match workers.choose(&mut thread_rng()) {
|
||||||
Some(worker) => Some(worker),
|
Some(worker) => Some(worker),
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
if result.is_none() {
|
if result.is_none() {
|
||||||
self.spawn();
|
self.spawn()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
@ -124,13 +120,13 @@ impl WorkerPool {
|
|||||||
/// message is sent to it.
|
/// message is sent to it.
|
||||||
pub fn execute(&self, f: impl (FnOnce() -> Promise) + Send + 'static) -> Result<(), JsValue> {
|
pub fn execute(&self, f: impl (FnOnce() -> Promise) + Send + 'static) -> Result<(), JsValue> {
|
||||||
let worker = self.worker()?;
|
let worker = self.worker()?;
|
||||||
let work = Box::new(Work { func: Box::new(f) });
|
let work = Work { func: Box::new(f) };
|
||||||
let ptr = Box::into_raw(work);
|
let work_ptr = Box::into_raw(Box::new(work));
|
||||||
match worker.post_message(&JsValue::from(ptr as u32)) {
|
match worker.post_message(&JsValue::from(work_ptr as u32)) {
|
||||||
Ok(()) => Ok(()),
|
Ok(()) => Ok(()),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
unsafe {
|
unsafe {
|
||||||
drop(Box::from_raw(ptr));
|
drop(Box::from_raw(work_ptr));
|
||||||
}
|
}
|
||||||
Err(e)
|
Err(e)
|
||||||
}
|
}
|
||||||
@ -140,23 +136,18 @@ impl WorkerPool {
|
|||||||
|
|
||||||
impl PoolState {
|
impl PoolState {
|
||||||
fn push(&self, worker: Worker) {
|
fn push(&self, worker: Worker) {
|
||||||
//worker.set_onmessage(Some(self.callback.as_ref().unchecked_ref()));
|
|
||||||
//worker.set_onerror(Some(self.callback.as_ref().unchecked_ref()));
|
|
||||||
let mut workers = self.workers.borrow_mut();
|
let mut workers = self.workers.borrow_mut();
|
||||||
for existing_worker in workers.iter() {
|
for existing_worker in workers.iter() {
|
||||||
assert!(existing_worker as &JsValue != &worker as &JsValue);
|
assert_ne!(existing_worker as &JsValue, &worker as &JsValue);
|
||||||
}
|
}
|
||||||
workers.push(worker);
|
workers.push(worker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Entry point invoked by `worker.js`, a bit of a hack but see the "TODO" above
|
/// Entry point invoked by the worker.
|
||||||
/// about `worker.js` in general.
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub async fn child_entry_point(ptr: u32) -> Result<(), JsValue> {
|
pub async fn multithreaded_worker_entry(ptr: u32) -> Result<(), JsValue> {
|
||||||
let ptr = unsafe { Box::from_raw(ptr as *mut Work) };
|
let ptr = unsafe { Box::from_raw(ptr as *mut Work) };
|
||||||
//let global = js_sys::global().unchecked_into::<DedicatedWorkerGlobalScope>();
|
|
||||||
JsFuture::from((ptr.func)()).await?;
|
JsFuture::from((ptr.func)()).await?;
|
||||||
//global.post_message(&JsValue::undefined())?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -1,34 +1,35 @@
|
|||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
|
||||||
use maplibre::{error::Error, io::scheduler::ScheduleMethod};
|
use log::warn;
|
||||||
|
use maplibre::{error::Error, io::scheduler::Scheduler};
|
||||||
use wasm_bindgen::{prelude::*, JsCast};
|
use wasm_bindgen::{prelude::*, JsCast};
|
||||||
use web_sys::Worker;
|
use web_sys::Worker;
|
||||||
|
|
||||||
use super::pool::WorkerPool;
|
use super::pool::WorkerPool;
|
||||||
|
|
||||||
pub struct WebWorkerPoolScheduleMethod {
|
pub struct WebWorkerPoolScheduler {
|
||||||
pool: WorkerPool,
|
pool: WorkerPool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WebWorkerPoolScheduleMethod {
|
impl WebWorkerPoolScheduler {
|
||||||
pub fn new(new_worker: js_sys::Function) -> Self {
|
pub fn new(new_worker: js_sys::Function) -> Self {
|
||||||
Self {
|
Self {
|
||||||
pool: WorkerPool::new(
|
pool: WorkerPool::new(
|
||||||
4,
|
1,
|
||||||
Box::new(move || {
|
Box::new(move || {
|
||||||
new_worker
|
new_worker
|
||||||
.call0(&JsValue::undefined())
|
.call0(&JsValue::undefined())
|
||||||
.unwrap()
|
.unwrap() // FIXME (wasm-executor): Remove unwrap
|
||||||
.dyn_into::<Worker>()
|
.dyn_into::<Worker>()
|
||||||
.unwrap()
|
.unwrap() // FIXME (wasm-executor): remove unwrap
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(), // FIXME (wasm-executor): Remove unwrap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScheduleMethod for WebWorkerPoolScheduleMethod {
|
impl Scheduler for WebWorkerPoolScheduler {
|
||||||
fn schedule<T>(
|
fn schedule<T>(
|
||||||
&self,
|
&self,
|
||||||
future_factory: impl (FnOnce() -> T) + Send + 'static,
|
future_factory: impl (FnOnce() -> T) + Send + 'static,
|
||||||
@ -43,7 +44,7 @@ impl ScheduleMethod for WebWorkerPoolScheduleMethod {
|
|||||||
Ok(JsValue::undefined())
|
Ok(JsValue::undefined())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap(); // FIXME (wasm-executor): remove unwrap
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
245
web/src/platform/singlethreaded/apc.rs
Normal file
245
web/src/platform/singlethreaded/apc.rs
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
use std::{
|
||||||
|
any::TypeId,
|
||||||
|
borrow::Borrow,
|
||||||
|
cell::RefCell,
|
||||||
|
collections::HashMap,
|
||||||
|
marker::PhantomData,
|
||||||
|
mem,
|
||||||
|
mem::{size_of, MaybeUninit},
|
||||||
|
ops::Deref,
|
||||||
|
pin::Pin,
|
||||||
|
rc::Rc,
|
||||||
|
sync::{
|
||||||
|
mpsc,
|
||||||
|
mpsc::{Receiver, Sender},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
use js_sys::Uint8Array;
|
||||||
|
use maplibre::{
|
||||||
|
environment::Environment,
|
||||||
|
io::{
|
||||||
|
apc::{AsyncProcedure, AsyncProcedureCall, Context, Input, Message},
|
||||||
|
scheduler::Scheduler,
|
||||||
|
source_client::{HttpClient, HttpSourceClient, SourceClient},
|
||||||
|
transferables::Transferables,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use wasm_bindgen::{prelude::*, JsCast, JsValue};
|
||||||
|
use web_sys::{DedicatedWorkerGlobalScope, Worker};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
platform::singlethreaded::transferables::{
|
||||||
|
InnerData, LinearTessellatedLayer, LinearTransferables,
|
||||||
|
},
|
||||||
|
MapType, WHATWGFetchHttpClient,
|
||||||
|
};
|
||||||
|
|
||||||
|
type UsedTransferables = LinearTransferables;
|
||||||
|
type UsedHttpClient = WHATWGFetchHttpClient;
|
||||||
|
type UsedContext = PassingContext;
|
||||||
|
|
||||||
|
enum SerializedMessageTag {
|
||||||
|
TileTessellated = 1,
|
||||||
|
UnavailableLayer = 2,
|
||||||
|
TessellatedLayer = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SerializedMessageTag {
|
||||||
|
fn from_u32(tag: u32) -> Option<Self> {
|
||||||
|
match tag {
|
||||||
|
x if x == SerializedMessageTag::UnavailableLayer as u32 => {
|
||||||
|
Some(SerializedMessageTag::UnavailableLayer)
|
||||||
|
}
|
||||||
|
x if x == SerializedMessageTag::TessellatedLayer as u32 => {
|
||||||
|
Some(SerializedMessageTag::TessellatedLayer)
|
||||||
|
}
|
||||||
|
x if x == SerializedMessageTag::TileTessellated as u32 => {
|
||||||
|
Some(SerializedMessageTag::TileTessellated)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait SerializableMessage {
|
||||||
|
fn serialize(&self) -> &[u8];
|
||||||
|
|
||||||
|
fn deserialize(tag: SerializedMessageTag, data: Uint8Array) -> Message<UsedTransferables>;
|
||||||
|
|
||||||
|
fn tag(&self) -> SerializedMessageTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SerializableMessage for Message<LinearTransferables> {
|
||||||
|
fn serialize(&self) -> &[u8] {
|
||||||
|
match self {
|
||||||
|
Message::TileTessellated(data) => bytemuck::bytes_of(data),
|
||||||
|
Message::UnavailableLayer(data) => bytemuck::bytes_of(data),
|
||||||
|
Message::TessellatedLayer(data) => bytemuck::bytes_of(data.data.as_ref()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize(tag: SerializedMessageTag, data: Uint8Array) -> Message<UsedTransferables> {
|
||||||
|
match tag {
|
||||||
|
SerializedMessageTag::TileTessellated => {
|
||||||
|
Message::<UsedTransferables>::TileTessellated(*bytemuck::from_bytes::<
|
||||||
|
<UsedTransferables as Transferables>::TileTessellated,
|
||||||
|
>(&data.to_vec()))
|
||||||
|
}
|
||||||
|
SerializedMessageTag::UnavailableLayer => {
|
||||||
|
Message::<UsedTransferables>::UnavailableLayer(*bytemuck::from_bytes::<
|
||||||
|
<UsedTransferables as Transferables>::UnavailableLayer,
|
||||||
|
>(&data.to_vec()))
|
||||||
|
}
|
||||||
|
SerializedMessageTag::TessellatedLayer => {
|
||||||
|
Message::<UsedTransferables>::TessellatedLayer(LinearTessellatedLayer {
|
||||||
|
data: unsafe {
|
||||||
|
let mut uninit = Box::<InnerData>::new_zeroed();
|
||||||
|
data.raw_copy_to_ptr(uninit.as_mut_ptr() as *mut u8);
|
||||||
|
let x = uninit.assume_init();
|
||||||
|
|
||||||
|
x
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tag(&self) -> SerializedMessageTag {
|
||||||
|
match self {
|
||||||
|
Message::TileTessellated(_) => SerializedMessageTag::TileTessellated,
|
||||||
|
Message::UnavailableLayer(_) => SerializedMessageTag::UnavailableLayer,
|
||||||
|
Message::TessellatedLayer(_) => SerializedMessageTag::TessellatedLayer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct PassingContext {
|
||||||
|
source_client: SourceClient<UsedHttpClient>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Context<UsedTransferables, UsedHttpClient> for PassingContext {
|
||||||
|
fn send(&self, data: Message<UsedTransferables>) {
|
||||||
|
let tag = data.tag();
|
||||||
|
let serialized = data.serialize();
|
||||||
|
|
||||||
|
let serialized_array_buffer = js_sys::ArrayBuffer::new(serialized.len() as u32);
|
||||||
|
let serialized_array = js_sys::Uint8Array::new(&serialized_array_buffer);
|
||||||
|
unsafe {
|
||||||
|
serialized_array.set(&Uint8Array::view(serialized), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let global = js_sys::global().unchecked_into::<DedicatedWorkerGlobalScope>(); // FIXME (wasm-executor): Remove unchecked
|
||||||
|
let array = js_sys::Array::new();
|
||||||
|
array.push(&JsValue::from(tag as u32));
|
||||||
|
array.push(&serialized_array_buffer);
|
||||||
|
global.post_message(&array).unwrap(); // FIXME (wasm-executor) Remove unwrap
|
||||||
|
}
|
||||||
|
|
||||||
|
fn source_client(&self) -> &SourceClient<UsedHttpClient> {
|
||||||
|
&self.source_client
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PassingAsyncProcedureCall {
|
||||||
|
new_worker: Box<dyn Fn() -> Worker>,
|
||||||
|
workers: Vec<Worker>,
|
||||||
|
|
||||||
|
received: Vec<Message<UsedTransferables>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PassingAsyncProcedureCall {
|
||||||
|
pub fn new(new_worker: js_sys::Function, initial_workers: u8) -> Self {
|
||||||
|
let create_new_worker = Box::new(move || {
|
||||||
|
new_worker
|
||||||
|
.call0(&JsValue::undefined())
|
||||||
|
.unwrap() // FIXME (wasm-executor): Remove unwrap
|
||||||
|
.dyn_into::<Worker>()
|
||||||
|
.unwrap() // FIXME (wasm-executor): Remove unwrap
|
||||||
|
});
|
||||||
|
|
||||||
|
let workers = (0..initial_workers)
|
||||||
|
.map(|_| {
|
||||||
|
let worker: Worker = create_new_worker();
|
||||||
|
|
||||||
|
let array = js_sys::Array::new();
|
||||||
|
array.push(&wasm_bindgen::module());
|
||||||
|
worker.post_message(&array).unwrap(); // FIXME (wasm-executor): Remove unwrap
|
||||||
|
worker
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
new_worker: create_new_worker,
|
||||||
|
workers,
|
||||||
|
received: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsyncProcedureCall<UsedTransferables, UsedHttpClient> for PassingAsyncProcedureCall {
|
||||||
|
type Context = UsedContext;
|
||||||
|
|
||||||
|
fn receive(&mut self) -> Option<Message<UsedTransferables>> {
|
||||||
|
self.received.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn schedule(&self, input: Input, procedure: AsyncProcedure<Self::Context>) {
|
||||||
|
let procedure_ptr = procedure as *mut AsyncProcedure<Self::Context> as u32; // FIXME (wasm-executor): is u32 fine, define an overflow safe function?
|
||||||
|
let input = serde_json::to_string(&input).unwrap(); // FIXME (wasm-executor): Remove unwrap
|
||||||
|
|
||||||
|
let array = js_sys::Array::new();
|
||||||
|
array.push(&JsValue::from(procedure_ptr));
|
||||||
|
array.push(&JsValue::from(input));
|
||||||
|
|
||||||
|
self.workers[0].post_message(&array).unwrap(); // FIXME (wasm-executor): Remove unwrap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Entry point invoked by the worker.
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub async fn singlethreaded_worker_entry(procedure_ptr: u32, input: String) -> Result<(), JsValue> {
|
||||||
|
let procedure: AsyncProcedure<UsedContext> = unsafe { std::mem::transmute(procedure_ptr) };
|
||||||
|
|
||||||
|
let input = serde_json::from_str::<Input>(&input).unwrap(); // FIXME (wasm-executor): Remove unwrap
|
||||||
|
|
||||||
|
let context = PassingContext {
|
||||||
|
source_client: SourceClient::Http(HttpSourceClient::new(WHATWGFetchHttpClient::new())),
|
||||||
|
};
|
||||||
|
|
||||||
|
(procedure)(input, context).await;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Entry point invoked by the main thread.
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub unsafe fn singlethreaded_main_entry(
|
||||||
|
map_ptr: *const RefCell<MapType>,
|
||||||
|
type_id: u32,
|
||||||
|
data: Uint8Array,
|
||||||
|
) -> Result<(), JsValue> {
|
||||||
|
// FIXME (wasm-executor): Can we make this call safe? check if it was cloned before?
|
||||||
|
let mut map = Rc::from_raw(map_ptr);
|
||||||
|
|
||||||
|
let message = Message::<UsedTransferables>::deserialize(
|
||||||
|
SerializedMessageTag::from_u32(type_id).unwrap(),
|
||||||
|
data,
|
||||||
|
);
|
||||||
|
|
||||||
|
map.deref()
|
||||||
|
.borrow()
|
||||||
|
.map_schedule()
|
||||||
|
.deref()
|
||||||
|
.borrow()
|
||||||
|
.apc
|
||||||
|
.deref()
|
||||||
|
.borrow_mut()
|
||||||
|
.received
|
||||||
|
.push(message);
|
||||||
|
|
||||||
|
mem::forget(map); // FIXME (wasm-executor): Enforce this somehow
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
2
web/src/platform/singlethreaded/mod.rs
Normal file
2
web/src/platform/singlethreaded/mod.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
pub mod apc;
|
||||||
|
pub mod transferables;
|
||||||
158
web/src/platform/singlethreaded/transferables.rs
Normal file
158
web/src/platform/singlethreaded/transferables.rs
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
use bytemuck::{TransparentWrapper, Zeroable};
|
||||||
|
use bytemuck_derive::{Pod, Zeroable};
|
||||||
|
use maplibre::{
|
||||||
|
benchmarking::tessellation::{IndexDataType, OverAlignedVertexBuffer},
|
||||||
|
coords::WorldTileCoords,
|
||||||
|
io::{
|
||||||
|
tile_repository::StoredLayer,
|
||||||
|
transferables::{TessellatedLayer, TileTessellated, Transferables, UnavailableLayer},
|
||||||
|
},
|
||||||
|
render::ShaderVertex,
|
||||||
|
tile::Layer,
|
||||||
|
};
|
||||||
|
|
||||||
|
// FIXME (wasm-executor): properly do this!, fix this whole file
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct WrapperWorldTileCoords(WorldTileCoords);
|
||||||
|
unsafe impl TransparentWrapper<WorldTileCoords> for WrapperWorldTileCoords {}
|
||||||
|
unsafe impl bytemuck::Zeroable for WrapperWorldTileCoords {}
|
||||||
|
unsafe impl bytemuck::Pod for WrapperWorldTileCoords {}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct LongVertexShader([ShaderVertex; 15000]);
|
||||||
|
unsafe impl TransparentWrapper<[ShaderVertex; 15000]> for LongVertexShader {}
|
||||||
|
unsafe impl bytemuck::Zeroable for LongVertexShader {}
|
||||||
|
unsafe impl bytemuck::Pod for LongVertexShader {}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct LongIndices([IndexDataType; 40000]);
|
||||||
|
unsafe impl TransparentWrapper<[IndexDataType; 40000]> for LongIndices {}
|
||||||
|
unsafe impl bytemuck::Zeroable for LongIndices {}
|
||||||
|
unsafe impl bytemuck::Pod for LongIndices {}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Pod, Zeroable)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct LinearTileTessellated {
|
||||||
|
pub coords: WrapperWorldTileCoords,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TileTessellated for LinearTileTessellated {
|
||||||
|
fn new(coords: WorldTileCoords) -> Self {
|
||||||
|
Self {
|
||||||
|
coords: WrapperWorldTileCoords::wrap(coords),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn coords(&self) -> &WorldTileCoords {
|
||||||
|
WrapperWorldTileCoords::peel_ref(&self.coords)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Pod, Zeroable)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct LinearUnavailableLayer {
|
||||||
|
pub coords: WrapperWorldTileCoords,
|
||||||
|
pub layer_name: [u8; 32],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UnavailableLayer for LinearUnavailableLayer {
|
||||||
|
fn new(coords: WorldTileCoords, layer_name: String) -> Self {
|
||||||
|
let mut new_layer_name = [0; 32];
|
||||||
|
new_layer_name[0..layer_name.len()].clone_from_slice(layer_name.as_bytes());
|
||||||
|
Self {
|
||||||
|
coords: WrapperWorldTileCoords::wrap(coords),
|
||||||
|
layer_name: new_layer_name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_stored_layer(self) -> StoredLayer {
|
||||||
|
StoredLayer::UnavailableLayer {
|
||||||
|
coords: WrapperWorldTileCoords::peel(self.coords),
|
||||||
|
layer_name: String::from_utf8(Vec::from(self.layer_name)).unwrap(), // FIXME (wasm-executor): Remove unwrap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Pod, Zeroable)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct InnerData {
|
||||||
|
pub coords: WrapperWorldTileCoords,
|
||||||
|
pub layer_name: [u8; 32],
|
||||||
|
pub layer_name_len: usize,
|
||||||
|
pub vertices: LongVertexShader,
|
||||||
|
pub vertices_len: usize,
|
||||||
|
pub indices: LongIndices,
|
||||||
|
pub indices_len: usize,
|
||||||
|
pub usable_indices: u32,
|
||||||
|
/// Holds for each feature the count of indices.
|
||||||
|
pub feature_indices: [u32; 2048],
|
||||||
|
pub feature_indices_len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct LinearTessellatedLayer {
|
||||||
|
pub data: Box<InnerData>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TessellatedLayer for LinearTessellatedLayer {
|
||||||
|
fn new(
|
||||||
|
coords: WorldTileCoords,
|
||||||
|
buffer: OverAlignedVertexBuffer<ShaderVertex, IndexDataType>,
|
||||||
|
feature_indices: Vec<u32>,
|
||||||
|
layer_data: Layer,
|
||||||
|
) -> Self {
|
||||||
|
let mut data = Box::new(InnerData {
|
||||||
|
coords: WrapperWorldTileCoords::wrap(coords),
|
||||||
|
|
||||||
|
layer_name: [0; 32],
|
||||||
|
layer_name_len: layer_data.name.len(),
|
||||||
|
|
||||||
|
vertices: LongVertexShader::wrap([ShaderVertex::zeroed(); 15000]),
|
||||||
|
vertices_len: buffer.buffer.vertices.len(),
|
||||||
|
|
||||||
|
indices: LongIndices::wrap([IndexDataType::zeroed(); 40000]),
|
||||||
|
indices_len: buffer.buffer.indices.len(),
|
||||||
|
|
||||||
|
usable_indices: buffer.usable_indices,
|
||||||
|
|
||||||
|
feature_indices: [0u32; 2048],
|
||||||
|
feature_indices_len: feature_indices.len(),
|
||||||
|
});
|
||||||
|
|
||||||
|
data.vertices.0[0..buffer.buffer.vertices.len()].clone_from_slice(&buffer.buffer.vertices);
|
||||||
|
data.indices.0[0..buffer.buffer.indices.len()].clone_from_slice(&buffer.buffer.indices);
|
||||||
|
data.feature_indices[0..feature_indices.len()].clone_from_slice(&feature_indices);
|
||||||
|
data.layer_name[0..layer_data.name.len()].clone_from_slice(layer_data.name.as_bytes());
|
||||||
|
|
||||||
|
Self { data }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_stored_layer(self) -> StoredLayer {
|
||||||
|
let layer = StoredLayer::TessellatedLayer {
|
||||||
|
coords: WrapperWorldTileCoords::peel(self.data.coords),
|
||||||
|
layer_name: String::from_utf8(Vec::from(
|
||||||
|
&self.data.layer_name[..self.data.layer_name_len],
|
||||||
|
))
|
||||||
|
.unwrap(), // FIXME (wasm-executor): Remove unwrap
|
||||||
|
buffer: OverAlignedVertexBuffer::from_slices(
|
||||||
|
&self.data.vertices.0[..self.data.vertices_len],
|
||||||
|
&self.data.indices.0[..self.data.indices_len],
|
||||||
|
self.data.usable_indices,
|
||||||
|
),
|
||||||
|
feature_indices: Vec::from(&self.data.feature_indices[..self.data.feature_indices_len]),
|
||||||
|
};
|
||||||
|
|
||||||
|
layer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LinearTransferables;
|
||||||
|
|
||||||
|
impl Transferables for LinearTransferables {
|
||||||
|
type TileTessellated = LinearTileTessellated;
|
||||||
|
type UnavailableLayer = LinearUnavailableLayer;
|
||||||
|
type TessellatedLayer = LinearTessellatedLayer;
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user