Skip to content

Commit a620450

Browse files
authored
Merge branch 'ArmDeveloperEcosystem:main' into content_review
2 parents 43fd5f0 + fcff75a commit a620450

11 files changed

Lines changed: 448 additions & 232 deletions

File tree

assets/contributors.csv

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ Mohamad Najem,Arm,,,,
105105
Ruifeng Wang,Arm,,,,
106106
Zenon Zhilong Xiu,Arm,,zenon-zhilong-xiu-491bb398,,
107107
Zbynek Roubalik,Kedify,,,,
108-
Rani Chowdary Mandepudi, Arm,,,,
108+
Rani Chowdary Mandepudi,Arm,,,,
109109
Ayoub Bourjilat,Ac6,Bourjilat,ayoub-bourjilat-a55b58165/,,https://www.ac6.fr/en/
110110
Yahya Abouelseoud,Arm,,,,
111+
Éliás Bálint,Arm,,,,
112+
Steve Suzuki,Arm,,,,

assets/css/content.css

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,14 @@ html[theme="dark"] div.markdown-content-div > div.code-tabpane {
6262
--ads-horizontal-tabs-tab-content-background-color: var(--arm-color-surface);
6363
}
6464

65-
65+
/*
6666
div.markdown-content-div > table {
67-
width: max-content; /* No full-length tables unless there is a reason */
67+
width: max-content;
6868
margin-top: 16px;
6969
margin-left: 16px;
7070
margin-bottom: 24px;
7171
}
72+
*/
7273
html[theme="light"] div.markdown-content-div > table tbody { background-color: var(--arm-white); }
7374
html[theme="dark"] div.markdown-content-div > table tbody { background-color: var(--arm-color-base); }
7475

assets/css/cross-page.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,7 @@ html[theme="dark"] .minhang-mist-text {
368368
.table-wrapper-for-overflow {
369369
width: 100%;
370370
overflow-x: auto;
371+
margin-top: 24px;
371372
}
372373

373374

content/learning-paths/mobile-graphics-and-gaming/android_halide/_index.md

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,21 @@
11
---
2-
title: Halide Essentials From Basics to Android Integration
3-
4-
draft: true
5-
cascade:
6-
draft: true
2+
title: Build high-performance image processing with Halide on Android
73

84
minutes_to_complete: 180
95

10-
who_is_this_for: This is an introductory topic for software developers interested in learning how to use Halide for image processing.
6+
who_is_this_for: This is an introductory topic for developers interested in learning how to use Halide for image processing.
117

128
learning_objectives:
13-
- Understand foundational concepts of Halide and set up your development environment.
14-
- Create a basic real-time image processing pipeline using Halide.
15-
- Optimize image processing workflows by applying operation fusion in Halide.
16-
- Integrate Halide pipelines into Android applications developed with Kotlin.
9+
- Learn the basics of Halide and set up your development environment
10+
- Build a simple real-time image processing pipeline with Halide
11+
- Make your image processing faster by combining operations in Halide
12+
- Use Halide pipelines in Android apps written with Kotlin
1713

1814
prerequisites:
1915
- Basic C++ knowledge
2016
- Android Studio with Android Emulator
2117

22-
author: Dawid Borycki
18+
author: Éliás Bálint, Dawid Borycki, Steve Suzuki
2319

2420
### Tags
2521
skilllevels: Introductory
@@ -31,15 +27,20 @@ operatingsystems:
3127
- Android
3228
tools_software_languages:
3329
- Android Studio
34-
- Coding
30+
- Halide
31+
- C++
32+
- Kotlin
33+
- Android Studio
34+
- CMake
35+
3536

3637
further_reading:
3738
- resource:
38-
title: Halide 19.0.0
39+
title: Halide documentation
3940
link: https://halide-lang.org/docs/index.html
4041
type: website
4142
- resource:
42-
title: Halide GitHub
43+
title: Halide GitHub repository
4344
link: https://github.com/halide/Halide
4445
type: repository
4546
- resource:

content/learning-paths/mobile-graphics-and-gaming/android_halide/android.md

Lines changed: 29 additions & 28 deletions
Large diffs are not rendered by default.

content/learning-paths/mobile-graphics-and-gaming/android_halide/aot-and-cross-compilation.md

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,25 @@
11
---
22
# User change
3-
title: "Ahead-of-time and cross-compilation"
3+
title: "Generate optimized Halide pipelines for Android using ahead-of-time cross-compilation"
44

55
weight: 5
66

77
layout: "learningpathall"
88
---
99

10-
## Ahead-of-time and cross-compilation
11-
One of Halide's standout features is the ability to compile image processing pipelines ahead-of-time (AOT), enabling developers to generate optimized binary code on their host machines rather than compiling directly on target devices. This AOT compilation process allows developers to create highly efficient libraries that run effectively across diverse hardware without incurring the runtime overhead associated with just-in-time (JIT) compilation.
1210

13-
Halide also supports robust cross-compilation capabilities. Cross-compilation means using the host version of Halide, typically running on a desktop Linux or macOS system—to target different architectures, such as ARM for Android devices. Developers can thus optimize Halide pipelines on their host machine, produce libraries specifically optimized for Android, and integrate them seamlessly into Android applications. The generated pipeline code includes essential optimizations and can embed minimal runtime support, further reducing workload on the target device and ensuring responsiveness and efficiency.
11+
## What you'll build
12+
In this section, you'll leverage the host version of Halide to perform AOT compilation of an image processing pipeline via cross-compilation. The resulting pipeline library is specifically tailored to Android devices (targeting, for instance, arm64-v8a ABI), while the compilation itself occurs entirely on the host system. This approach significantly accelerates development by eliminating the need to build Halide or perform JIT compilation on Android devices. It also guarantees that the resulting binaries are optimized for the intended hardware, streamlining the deployment of high-performance image processing applications on mobile platforms.
1413

15-
## Objective
16-
In this section, we leverage the host version of Halide to perform AOT compilation of an image processing pipeline via cross-compilation. The resulting pipeline library is specifically tailored to Android devices (targeting, for instance, arm64-v8a ABI), while the compilation itself occurs entirely on the host system. This approach significantly accelerates development by eliminating the need to build Halide or perform JIT compilation on Android devices. It also guarantees that the resulting binaries are optimized for the intended hardware, streamlining the deployment of high-performance image processing applications on mobile platforms.
1714

18-
## Prepare Pipeline for Android
19-
The procedure implemented in the following code demonstrates how Halide's AOT compilation and cross-compilation features can be utilized to create an optimized image processing pipeline for Android. We will run Halide on our host machine (in this example, macOS) to generate a static library containing the pipeline function, which will later be invoked from an Android device. Below is a step-by-step explanation of this process.
15+
## Learn about ahead-of-time (AOT) and cross-compilation
16+
One of Halide's standout features is the ability to compile image processing pipelines ahead-of-time (AOT), enabling you to generate optimized binary code on your host machine rather than compiling directly on target devices. This AOT compilation process enables you to create highly efficient libraries that run effectively across diverse hardware without incurring the runtime overhead associated with just-in-time (JIT) compilation.
17+
18+
Halide also supports robust cross-compilation capabilities. Cross-compilation means using the host version of Halide, typically running on a desktop Linux or macOS system—to target different architectures, such as Arm for Android devices. You can optimize Halide pipelines on your host machine, produce libraries specifically optimized for Android, and integrate them seamlessly into Android applications. The generated pipeline code includes essential optimizations and can embed minimal runtime support, further reducing workload on the target device and ensuring responsiveness and efficiency.
19+
20+
21+
## Prepare pipeline for Android
22+
The following code demonstrates how to use Halide's AOT compilation and cross-compilation features to create an optimized image processing pipeline for Android. Run Halide on your host machine (in this example, macOS) to generate a static library containing the pipeline function, which you'll later invoke from an Android device. Below is a step-by-step explanation of this process.
2023

2124
Create a new file named blur-android.cpp with the following contents:
2225

@@ -85,9 +88,9 @@ int main(int argc, char** argv) {
8588
}
8689
```
8790
88-
In the original implementation constants 128, 255, and 0 were implicitly treated as integers. Here, the threshold value (128) and output values (255, 0) are explicitly cast to uint8_t. This approach removes ambiguity and clearly specifies the types used, ensuring compatibility and clarity. Both approaches result in identical functionality, but explicitly casting helps emphasize the type correctness and may avoid subtle issues during cross-compilation or in certain environments. Additionally, explicit uint8_t casts help avoid implicit promotion to 32-bit integers (and the corresponding narrowings back to 8-bit) in the generated code, reducing redundant cast operations and potential vector widen/narrow overhead—especially on ARM/NEON
91+
In the original implementation constants 128, 255, and 0 were implicitly treated as integers. Here, the threshold value (128) and output values (255, 0) are explicitly cast to uint8_t. This approach removes ambiguity and clearly specifies the types used, ensuring compatibility and clarity. Both approaches result in identical functionality, but explicitly casting helps emphasize the type correctness and may avoid subtle issues during cross-compilation or in certain environments. Additionally, explicit uint8_t casts help avoid implicit promotion to 32-bit integers (and the corresponding narrowings back to 8-bit) in the generated code, reducing redundant cast operations and potential vector widen/narrow overhead—especially on Arm/NEON.
8992
90-
The program takes at least one command-line argument, the output base name used to generate the files (e.g., “blur_threshold_android). Here, the target architecture is explicitly set within the code to Android ARM64:
93+
The program takes at least one command-line argument, the output base name used to generate the files (for example, "blur_threshold_android"). Here, the target architecture is explicitly set within the code to Android ARM64:
9194
9295
```cpp
9396
// Configure Halide Target for Android
@@ -99,30 +102,30 @@ target.bits = 64;
99102
// Enable Halide runtime inclusion in the generated library (needed if not linking Halide runtime separately).
100103
target.set_feature(Target::NoRuntime, false);
101104
102-
// Optionally, enable hardware-specific optimizations to improve performance on ARM devices:
103-
// - DotProd: Optimizes matrix multiplication and convolution-like operations on ARM.
105+
// Optionally, enable hardware-specific optimizations to improve performance on Arm devices:
106+
// - DotProd: Optimizes matrix multiplication and convolution-like operations on Arm.
104107
// - ARMFp16 (half-precision floating-point operations).
105108
```
106109

107110
Notes:
108111
1. NoRuntime — When set to true, Halide excludes its runtime from the generated code, and you must link the runtime manually during the linking step. When set to false, the Halide runtime is included in the generated library, which simplifies deployment.
109-
2. ARMFp16 — Enables the use of ARM hardware support for half-precision (16-bit) floating-point operations, which can provide faster execution when reduced precision is acceptable.
112+
2. ARMFp16 — Enables the use of Arm hardware support for half-precision (16-bit) floating-point operations, which improves execution speed when reduced precision is acceptable.
110113
3. Why the runtime choice matters - If your app links several AOT-compiled pipelines, ensure there is exactly one Halide runtime at link time:
111-
* Strategy A (cleanest): build all pipelines with NoRuntime ON and link a single standalone Halide runtime once (matching the union of features you need, e.g., Vulkan/OpenCL/Metal or ARM options).
114+
* Strategy A (cleanest): build all pipelines with NoRuntime ON and link a single standalone Halide runtime once (matching the union of features you need, for example, Vulkan/OpenCL/Metal or Arm options).
112115
* Strategy B: embed the runtime in exactly one pipeline (leave NoRuntime OFF only there); compile all other pipelines with NoRuntime ON.
113116
* Mixing more than one runtime can cause duplicate symbols and split global state (e.g., error handlers, device interfaces).
114117

115-
We declare spatial variables (x, y) and an ImageParam named input representing the input image data. We use boundary clamping (clamp) to safely handle edge pixels. Then, we apply a 3x3 blur with a reduction domain (RDom). The accumulated sum is divided by 9 (the number of pixels in the neighborhood), producing an average blurred image. Lastly, thresholding is applied, producing a binary output: pixels above a certain brightness threshold (128) become white (255), while others become black (0).
118+
The code declares spatial variables (x, y) and an ImageParam named "input" representing the input image data. Boundary clamping (clamp) safely handles edge pixels. A 3×3 blur with a reduction domain (RDom) is then applied. The accumulated sum is divided by 9 (the number of pixels in the neighborhood), producing an average blurred image. Lastly, thresholding is applied, producing a binary output: pixels above a certain brightness threshold (128) become white (255), while others become black (0).
116119

117120
This section intentionally reinforces previous concepts, focusing now primarily on explicitly clarifying integration details, such as type correctness and the handling of runtime features within Halide.
118121

119122
Simple scheduling directives (compute_root) instruct Halide to compute intermediate functions at the pipeline’s root, simplifying debugging and potentially enhancing runtime efficiency.
120123

121124
This strategy can simplify debugging by clearly isolating computational steps and may enhance runtime efficiency by explicitly controlling intermediate storage locations.
122125

123-
By clearly separating algorithm logic from scheduling, developers can easily test and compare different scheduling strategies,such as compute_inline, compute_root, compute_at, and more, without modifying their fundamental algorithmic code. This separation significantly accelerates iterative optimization and debugging processes, ultimately yielding better-performing code with minimal overhead.
126+
By clearly separating algorithm logic from scheduling, you can easily test and compare different scheduling strategies, such as compute_inline, compute_root, compute_at, and more, without modifying your fundamental algorithmic code. This separation significantly accelerates iterative optimization and debugging processes, ultimately yielding better-performing code with minimal overhead.
124127

125-
We invoke Halide's AOT compilation function compile_to_static_library, which generates a static library (.a) containing the optimized pipeline and a corresponding header file (.h).
128+
Halide's AOT compilation function compile_to_static_library generates a static library (.a) containing the optimized pipeline and a corresponding header file (.h).
126129

127130
```cpp
128131
thresholded.compile_to_static_library(
@@ -134,18 +137,18 @@ thresholded.compile_to_static_library(
134137
```
135138
136139
This will produce:
137-
* A static library (blur_threshold_android.a) containing the compiled pipeline. This static library also includes Halide's runtime functions tailored specifically for the targeted architecture (arm-64-android). Thus, no separate Halide runtime needs to be provided on the Android device when linking against this library.
140+
* A static library (blur_threshold_android.a) containing the compiled pipeline. This static library also includes Halide's runtime functions tailored specifically for the targeted architecture (arm-64-android). Thus, no separate Halide runtime needs to be provided on the Android device when linking against this library.
138141
* A header file (blur_threshold_android.h) declaring the pipeline function for use in other C++/JNI code.
139142
140143
These generated files are then ready to integrate directly into an Android project via JNI, allowing efficient execution of the optimized pipeline on Android devices. The integration process is covered in the next section.
141144
142-
Note: JNI (Java Native Interface) is a framework that allows Java (or Kotlin) code running in a Java Virtual Machine (JVM), such as on Android, to interact with native applications and libraries written in languages like C or C++. JNI bridges the managed Java/Kotlin environment and the native, platform-specific implementations.
145+
JNI (Java Native Interface) is a framework that allows Java (or Kotlin) code running in a Java Virtual Machine (JVM), such as on Android, to interact with native applications and libraries written in languages like C or C++. JNI bridges the managed Java/Kotlin environment and the native, platform-specific implementations.
143146
144-
## Compilation instructions
147+
## Compile the pipeline
145148
To compile the pipeline-generation program on your host system, use the following commands (replace /path/to/halide with your Halide installation directory):
146149
```console
147150
export DYLD_LIBRARY_PATH=/path/to/halide/lib/libHalide.19.dylib
148-
g++ -std=c++17 blud-android.cpp -o blud-android \
151+
g++ -std=c++17 blur-android.cpp -o blur-android \
149152
-I/path/to/halide/include -L/path/to/halide/lib -lHalide \
150153
$(pkg-config --cflags --libs opencv4) -lpthread -ldl \
151154
-Wl,-rpath,/path/to/halide/lib
@@ -160,7 +163,7 @@ This will produce two files:
160163
* blur_threshold_android.a: The static library containing your Halide pipeline.
161164
* blur_threshold_android.h: The header file needed to invoke the generated pipeline.
162165

163-
We will integrate these files into our Android project in the following section.
166+
You'll integrate these files into the Android project in the following section.
164167

165168
## Summary
166-
In this section, we’ve explored Halide's powerful ahead-of-time (AOT) and cross-compilation capabilities, preparing an optimized image processing pipeline tailored specifically for Android devices. By using the host-based Halide compiler, we’ve generated a static library optimized for ARM64 Android architecture, incorporating safe boundary conditions, neighborhood-based blurring, and thresholding operations. This streamlined process allows seamless integration of highly optimized native code into Android applications, ensuring both development efficiency and runtime performance on mobile platforms.
169+
You've explored Halide's powerful ahead-of-time (AOT) and cross-compilation capabilities, preparing an optimized image processing pipeline tailored specifically for Android devices. By using the host-based Halide compiler, you generated a static library optimized for 64-bit Arm Android architecture, incorporating safe boundary conditions, neighborhood-based blurring, and thresholding operations. This streamlined process allows seamless integration of highly optimized native code into Android applications, ensuring both development efficiency and runtime performance on mobile platforms.

0 commit comments

Comments
 (0)