Skip to content

Commit d3ad835

Browse files
mapatel-amdclaude
andauthored
feature: Conversion of HSOpticalFlow Program to HIP (#453)
* feature: Conversion of HSOpticalFlow Program to HIP * Remove tracked binary and fix stb_image include path * fix: README linting errors * fix: hip detection and compiling * fix: ppm data can now be found no matter where you are * fix: address PR review feedback for optical_flow - Add #include <hip/hip_runtime.h> to derivativesKernel.hip and downscaleKernel.hip (reviewer request for self-contained headers) - Fix LoadImageAsFP32 docstring: loads RGB (3-channel), not 4-channel - Update copyright year to 2026 in CMakeLists.txt and Makefile - Add optical_flow to Applications/Makefile EXAMPLES list - Add optical_flow entry to root README.md - Remove accidental .venv/ entry from root .gitignore - Rewrite optical_flow README with accurate build/run instructions: correct CMake compiler flag (clang++ not hipcc), ROCM_PATH and LD_LIBRARY_PATH env vars, working-directory-independent run instructions Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com> * fix: Add hip_runtime to all needed files --------- Co-authored-by: Claude Sonnet 4 <noreply@anthropic.com>
1 parent cf369da commit d3ad835

23 files changed

Lines changed: 13430 additions & 1 deletion

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@
88
CMakeUserPresets.json
99
.cline_storage
1010
config.mk
11-
.claude/
11+
.claude/

Applications/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ add_subdirectory(convolution)
4242
add_subdirectory(floyd_warshall)
4343
add_subdirectory(histogram)
4444
add_subdirectory(prefix_sum)
45+
add_subdirectory(optical_flow)
4546

4647
if(NOT CXX_FS_HEADER_FOUND)
4748
message(WARNING "filesystem not found, not building fdtd example")

Applications/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ EXAMPLES := \
2626
fdtd \
2727
floyd_warshall \
2828
histogram \
29+
optical_flow \
2930
prefix_sum
3031

3132
SKIP_FROM_TEST :=
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
applications_optical_flow
2+
*.flo
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# MIT License
2+
#
3+
# Copyright (c) 2023-2026 Advanced Micro Devices, Inc. All rights reserved.
4+
#
5+
# Permission is hereby granted, free of charge, to any person obtaining a copy
6+
# of this software and associated documentation files (the "Software"), to deal
7+
# in the Software without restriction, including without limitation the rights
8+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
# copies of the Software, and to permit persons to whom the Software is
10+
# furnished to do so, subject to the following conditions:
11+
#
12+
# The above copyright notice and this permission notice shall be included in all
13+
# copies or substantial portions of the Software.
14+
#
15+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
# SOFTWARE.
22+
23+
set(example_name applications_optical_flow)
24+
25+
cmake_minimum_required(VERSION 3.21 FATAL_ERROR)
26+
project(${example_name} LANGUAGES CXX)
27+
28+
include("${CMAKE_CURRENT_LIST_DIR}/../../Common/HipPlatform.cmake")
29+
select_gpu_language()
30+
31+
enable_language(${ROCM_EXAMPLES_GPU_LANGUAGE})
32+
set(CMAKE_CXX_STANDARD 17)
33+
set(CMAKE_CXX_EXTENSIONS OFF)
34+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
35+
set(CMAKE_${ROCM_EXAMPLES_GPU_LANGUAGE}_STANDARD 17)
36+
set(CMAKE_${ROCM_EXAMPLES_GPU_LANGUAGE}_EXTENSIONS OFF)
37+
set(CMAKE_${ROCM_EXAMPLES_GPU_LANGUAGE}_STANDARD_REQUIRED ON)
38+
select_hip_platform()
39+
40+
include("${CMAKE_CURRENT_LIST_DIR}/../../Common/ROCmPath.cmake")
41+
42+
add_executable(${example_name} main.hip flowHIP.hip flowGold.cpp)
43+
add_test(NAME ${example_name} COMMAND ${example_name})
44+
45+
set(include_dirs "../../Common")
46+
if(ROCM_EXAMPLES_HIP_PLATFORM STREQUAL "nvidia")
47+
list(APPEND include_dirs "${ROCM_PATH}/include")
48+
endif()
49+
50+
target_include_directories(${example_name} PRIVATE ${include_dirs})
51+
set_source_files_properties(main.hip flowHIP.hip PROPERTIES LANGUAGE ${ROCM_EXAMPLES_GPU_LANGUAGE})
52+
53+
install(TARGETS ${example_name})

Applications/optical_flow/Makefile

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# MIT License
2+
#
3+
# Copyright (c) 2022-2026 Advanced Micro Devices, Inc. All rights reserved.
4+
#
5+
# Permission is hereby granted, free of charge, to any person obtaining a copy
6+
# of this software and associated documentation files (the "Software"), to deal
7+
# in the Software without restriction, including without limitation the rights
8+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
# copies of the Software, and to permit persons to whom the Software is
10+
# furnished to do so, subject to the following conditions:
11+
#
12+
# The above copyright notice and this permission notice shall be included in all
13+
# copies or substantial portions of the Software.
14+
#
15+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
# SOFTWARE.
22+
23+
EXAMPLE := applications_optical_flow
24+
COMMON_INCLUDE_DIR := ../../Common
25+
GPU_RUNTIME ?= HIP
26+
27+
ROCM_PATH ?= /opt/rocm
28+
HIP_INCLUDE_DIR := $(ROCM_PATH)/include
29+
30+
HIPCXX ?= $(ROCM_PATH)/bin/hipcc
31+
32+
CXX_STD := c++17
33+
ICXXFLAGS := -std=$(CXX_STD)
34+
ICPPFLAGS := -I $(COMMON_INCLUDE_DIR)
35+
ILDFLAGS :=
36+
ILDLIBS :=
37+
38+
ifeq ($(GPU_RUNTIME), CUDA)
39+
ICXXFLAGS += -x cu
40+
ICPPFLAGS += -isystem $(HIP_INCLUDE_DIR)
41+
else ifeq ($(GPU_RUNTIME), HIP)
42+
CXXFLAGS ?= -Wall -Wextra
43+
else
44+
$(error GPU_RUNTIME is set to "$(GPU_RUNTIME)". GPU_RUNTIME must be either CUDA or HIP)
45+
endif
46+
47+
ICXXFLAGS += $(CXXFLAGS)
48+
ICPPFLAGS += $(CPPFLAGS)
49+
ILDFLAGS += $(LDFLAGS)
50+
ILDLIBS += $(LDLIBS)
51+
52+
$(EXAMPLE): main.hip flowHIP.hip flowGold.cpp $(COMMON_INCLUDE_DIR)/example_utils.hpp
53+
$(HIPCXX) $(ICXXFLAGS) $(ICPPFLAGS) $(ILDFLAGS) -o $@ main.hip flowHIP.hip flowGold.cpp $(ILDLIBS)
54+
55+
test: $(EXAMPLE)
56+
./$(EXAMPLE) $(TEST_ARGS)
57+
58+
clean:
59+
$(RM) $(EXAMPLE)
60+
61+
.PHONY: clean test
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# Optical Flow
2+
3+
## Description
4+
5+
This example implements the **Horn-Schunck variational optical flow** algorithm using HIP. It estimates the motion field (displacement vectors) between two consecutive image frames by minimizing a global energy functional that balances data fidelity and spatial smoothness.
6+
7+
The algorithm operates on a Gaussian image pyramid: flow is computed coarse-to-fine, with each level refining the estimate from the level above. At each pyramid level, image warping aligns the target frame with the source, and a Jacobi iterative solver computes the incremental flow update.
8+
9+
The program computes optical flow on both the CPU (`flowGold`) and GPU (`flowHIP`), compares the results via L1 norm, and writes two `.flo` files (Middlebury format) for inspection.
10+
11+
## Application Flow
12+
13+
1. Load two consecutive frames (`data/frame10.ppm`, `data/frame11.ppm`) as single-channel FP32 images.
14+
2. Build a Gaussian pyramid with `nLevels` levels by repeatedly downscaling with a 4-tap filter.
15+
3. At each pyramid level (coarse to fine):
16+
- Upscale the flow estimate from the coarser level.
17+
- Warp the target image toward the source using the current flow estimate.
18+
- Compute image derivatives (Ix, Iy, Iz) via finite differences.
19+
- Run `nSolverIters` Jacobi iterations to solve for the incremental flow update.
20+
- Repeat for `nWarpIters` warping passes.
21+
4. Copy GPU results to host and compare against the CPU reference (L1 norm per pixel).
22+
5. Write `FlowGPU.flo` and `FlowCPU.flo` to the working directory.
23+
24+
## Key APIs and Concepts
25+
26+
| Concept | HIP API |
27+
|---|---|
28+
| Texture objects with bilinear filtering | `hipCreateTextureObject`, `hipTextureObject_t` |
29+
| Pitched 2D texture resource | `hipResourceTypePitch2D`, `hipResourceDesc` |
30+
| Mirror address mode | `hipAddressModeMirror` |
31+
| Normalized texture coordinates | `texDescr.normalizedCoords = true` |
32+
| In-kernel texture fetch | `tex2D<float>(tex, x, y)` |
33+
| Block synchronization | `cg::this_thread_block()`, `cg::sync()` |
34+
35+
### Pitch Alignment Requirement
36+
37+
ROCm requires `pitchInBytes` for `hipResourceTypePitch2D` to be a multiple of **256 bytes** (64 floats × 4 bytes). The `STRIDE_ALIGNMENT` constant in `common.h` is set to `64` to satisfy this constraint. CUDA only requires 128 bytes (32 floats), so porting code that used `StrideAlignment = 32` will fail at texture creation.
38+
39+
## Prerequisites
40+
41+
- A ROCm-capable AMD GPU
42+
- ROCm SDK installed ([installation guide](https://rocm.docs.amd.com/en/latest/index.html) or [TheRock releases](https://github.com/ROCm/TheRock/blob/main/RELEASES.md))
43+
44+
## Building
45+
46+
Set `ROCM_PATH` to your ROCm installation root before building. For a standard system install:
47+
48+
```bash
49+
export ROCM_PATH=/opt/rocm
50+
```
51+
52+
For a Python venv-based install (e.g. TheRock):
53+
54+
```bash
55+
export ROCM_PATH=/path/to/venv/lib/python3.12/site-packages/_rocm_sdk_devel
56+
```
57+
58+
### Make
59+
60+
```bash
61+
cd Applications/optical_flow
62+
make ROCM_PATH=$ROCM_PATH
63+
```
64+
65+
If your ROCm device libraries are not found automatically, pass their path explicitly:
66+
67+
```bash
68+
make ROCM_PATH=$ROCM_PATH \
69+
CXXFLAGS="--rocm-device-lib-path=$ROCM_PATH/lib/llvm/amdgcn/bitcode"
70+
```
71+
72+
### CMake
73+
74+
CMake 3.28 and later require passing `clang++` directly rather than the `hipcc` wrapper script:
75+
76+
```bash
77+
cd Applications/optical_flow
78+
cmake -B build \
79+
-DROCM_PATH=$ROCM_PATH \
80+
-DCMAKE_HIP_COMPILER=$ROCM_PATH/lib/llvm/bin/clang++
81+
cmake --build build -j$(nproc)
82+
```
83+
84+
## Running
85+
86+
If ROCm is not installed to a standard system path, set `LD_LIBRARY_PATH` so the runtime libraries can be found:
87+
88+
```bash
89+
export LD_LIBRARY_PATH=$ROCM_PATH/lib:$LD_LIBRARY_PATH
90+
```
91+
92+
The binary locates the sample frames (`data/frame10.ppm`, `data/frame11.ppm`) relative to the source directory automatically, so it can be run from any working directory:
93+
94+
```bash
95+
# Make build
96+
./applications_optical_flow
97+
98+
# CMake build
99+
./build/applications_optical_flow
100+
```
101+
102+
### Expected Output
103+
104+
```text
105+
HSOpticalFlow Starting...
106+
107+
Using device: <GPU name>
108+
Loading "<source-dir>/data/frame10.ppm" ...
109+
Loading "<source-dir>/data/frame11.ppm" ...
110+
Computing optical flow on CPU...
111+
Computing optical flow on GPU...
112+
L1 error : 0.000xxx
113+
```
114+
115+
The program exits with `EXIT_SUCCESS` when the L1 error between the GPU and CPU results is below `0.05`. Two output files are written to the current working directory:
116+
117+
- `FlowGPU.flo` — GPU optical flow result
118+
- `FlowCPU.flo` — CPU reference result
119+
120+
Both files use the [Middlebury `.flo` format](http://vision.middlebury.edu/flow/code/flow-code/README.txt) and can be visualized with tools such as `flowiz` or the Middlebury flow utilities.
121+
122+
## Key Notes
123+
124+
- `STRIDE_ALIGNMENT` is 64 because `hipResourceTypePitch2D` requires `pitchInBytes` to be a multiple of 256 bytes (4 bytes × 64 floats = 256 bytes).
125+
- CMake 3.28+ does not accept the `hipcc` wrapper as `CMAKE_HIP_COMPILER`. Pass the `clang++` binary from `$ROCM_PATH/lib/llvm/bin/clang++` instead.
126+
- The binary resolves the input image paths relative to the source file location at compile time (via `__FILE__`/`/proc/self/exe`), so no specific working directory is required at runtime.
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// MIT License
2+
//
3+
// Copyright (c) 2023-2026 Advanced Micro Devices, Inc. All rights reserved.
4+
//
5+
// Permission is hereby granted, free of charge, to any person obtaining a copy
6+
// of this software and associated documentation files (the "Software"), to deal
7+
// in the Software without restriction, including without limitation the rights
8+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
// copies of the Software, and to permit persons to whom the Software is
10+
// furnished to do so, subject to the following conditions:
11+
//
12+
// The above copyright notice and this permission notice shall be included in all
13+
// copies or substantial portions of the Software.
14+
//
15+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
// SOFTWARE.
22+
23+
#include "common.h"
24+
25+
///////////////////////////////////////////////////////////////////////////////
26+
/// \brief add two vectors of size _count_
27+
///
28+
/// HIP kernel
29+
/// \param[in] op1 term one
30+
/// \param[in] op2 term two
31+
/// \param[in] count vector size
32+
/// \param[out] sum result
33+
///////////////////////////////////////////////////////////////////////////////
34+
__global__ void AddKernel(const float *op1, const float *op2, int count, float *sum)
35+
{
36+
const int pos = threadIdx.x + blockIdx.x * blockDim.x;
37+
38+
if (pos >= count)
39+
return;
40+
41+
sum[pos] = op1[pos] + op2[pos];
42+
}
43+
44+
///////////////////////////////////////////////////////////////////////////////
45+
/// \brief add two vectors of size _count_
46+
/// \param[in] op1 term one
47+
/// \param[in] op2 term two
48+
/// \param[in] count vector size
49+
/// \param[out] sum result
50+
///////////////////////////////////////////////////////////////////////////////
51+
static void Add(const float *op1, const float *op2, int count, float *sum)
52+
{
53+
dim3 threads(256);
54+
dim3 blocks(iDivUp(count, threads.x));
55+
56+
AddKernel<<<blocks, threads>>>(op1, op2, count, sum);
57+
}

Applications/optical_flow/common.h

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// MIT License
2+
//
3+
// Copyright (c) 2023-2026 Advanced Micro Devices, Inc. All rights reserved.
4+
//
5+
// Permission is hereby granted, free of charge, to any person obtaining a copy
6+
// of this software and associated documentation files (the "Software"), to deal
7+
// in the Software without restriction, including without limitation the rights
8+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
// copies of the Software, and to permit persons to whom the Software is
10+
// furnished to do so, subject to the following conditions:
11+
//
12+
// The above copyright notice and this permission notice shall be included in all
13+
// copies or substantial portions of the Software.
14+
//
15+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
// SOFTWARE.
22+
23+
#pragma once
24+
25+
#include <cmath>
26+
#include <cstdio>
27+
#include <cstdlib>
28+
#include <cstring>
29+
30+
// HIP hipResourceTypePitch2D requires pitchInBytes to be a multiple of 256 bytes.
31+
// 64 floats * 4 bytes = 256 bytes satisfies this
32+
constexpr int STRIDE_ALIGNMENT = 64;
33+
34+
inline int iAlignUp(int n, int m = STRIDE_ALIGNMENT)
35+
{
36+
int mod = n % m;
37+
if (mod)
38+
return n + m - mod;
39+
else
40+
return n;
41+
}
42+
43+
inline int iDivUp(int n, int m) { return (n + m - 1) / m; }
44+
45+
template <typename T> inline void Swap(T &a, T &b)
46+
{
47+
T t = a;
48+
a = b;
49+
b = t;
50+
}

0 commit comments

Comments
 (0)