GPU Usage Guide

The GPU (Graphics Processing Unit) is a dedicated processor in a device that is primarily responsible for graphics rendering and image processing. If a device is compared to a computer:

  • The CPU is responsible for “thinking” — processing logic and running programs.

  • The GPU is responsible for “drawing” — rendering content into images displayed on the screen.

Without a GPU, graphical interfaces, games, videos, and animations cannot be rendered efficiently. GPU performance directly affects the smoothness of graphics processing and the power consumption of the device.

Use Case

Description

System UI

Boot animations, desktop rendering, application switching, drop-down menus, and other UI rendering

Gaming & Entertainment

3D games, animation effects, AR applications, and other graphics rendering

Video Playback

Video color processing, image enhancement, and HDR effects

Camera & Photography

Viewfinder rendering, filter effects, and image enhancement

General Computing

Assists the CPU with parallel computing, such as face recognition and AI application acceleration

GPU Configuration


Category


M1 Description


L1 Description

Application Processor

Octa-core 64-bit ARM Kryo™ 260 processor:
4 × A73 @ 2.0 GHz, 1 MB L2 cache
4 × A53 @ 1.8 GHz, 512 KB L2 cache

Quad-core 64-bit ARM processor:
4 × A53 @ 2.0 GHz, 512 KB L2 cache

GPU

64-bit Adreno™ 610 @ 1050 MHz

64-bit Adreno™ 702 @ 845 MHz

Display Interface

1 × Micro HDMI interface, Micro HDMI 2.0 (frame rate*); Encoding: 1080p (H.264/H.265) @ 60 fps*; Decoding: 1080p (H.264/H.265/VP9) @ 60 fps*
1 × FPC connector, MIPI-compliant FHD+ (1080 × 2520) @ 60 fps*

1 × Micro HDMI interface①, HDMI 2.0 (frame rate TBD*); Encoding: 1080p (H.264/H.265) @ 60 fps*; Decoding: 1080p (H.264/H.265/VP9) @ 60 fps*
1 × FPC connector①, MIPI-compliant FHD+ (1080 × 2520) @ 60 fps*

GPU Usage

Android 4K High-Definition Video Playback

../../_images/image_F2GRbtmaWoXZiuxS5qccFZM5n3t.webp

Debian OpenCV GPU Acceleration Development and Verification

Preparation

Development Environment

  • PC: Windows

  • Development Board: Quectel Pi M1

  • Operating System: Debian GNU/Linux 13

Development Tools

  • VS Code: Used to write and modify the Benchmark source code.

  • ADB (Android Debug Bridge): Used to connect to the development board, execute Linux commands, compile programs, and run applications.

Note: Except for source code editing, all Linux commands described in this document, including software installation, environment verification, program compilation, and program execution, are executed in the ADB Shell.

Connect to the Development Board

On the PC, open the ADB folder, enter CMD in the address bar to open a command prompt, and run:

adb devices

Confirm that the development board is connected. For example:

List of devices attached
xxxxxxxx    device

Enter the development board:

adb shell

Test Purpose

Install the official Debian OpenCV 4.10.0 package and verify whether Debian can use the Qualcomm OpenCL Runtime included in the system image to access the Adreno GPU and enable OpenCL GPU acceleration.

Test Environment

Item


Details

Development Board

Quectel Pi M1(QSM200U)

Operating System

Debian GNU/Linux 13

Debian OpenCV

4.10.0

GPU

Qualcomm Adreno 610

OpenCL Runtime

Qualcomm OpenCL Runtime

Install OpenCV from the Official Debian Repository

apt update
apt install g++ pkg-config libopencv-dev python3-opencv

Verify the installation after it is complete:

opencv_version
pkg-config --modversion opencv4
dpkg -l | grep opencv

Verification results:

  • opencv_version: 4.10.0

  • pkg-config: 4.10.0

  • dpkg: Debian OpenCV 4.10.0

Verify the OpenCL Runtime

Check the OpenCL libraries available in the system:

find /usr/lib -name "libOpenCL*"

Confirm that the following libraries are present:

libOpenCL.so
libOpenCL.so.1
libOpenCL.so.1.2
libOpenCL_adreno.so

Write the Benchmark Program

Create the opencv_gpu_benchmark.cpp file in VS Code.

#include <opencv2/core.hpp>
#include <opencv2/core/ocl.hpp>
#include <iostream>
#include <string>

static double run_cpu(const cv::Mat &src, int loops, cv::Mat &result)
{
    cv::ocl::setUseOpenCL(false);

    cv::Mat current = src.clone();
    cv::Mat next;

    for (int i = 0; i < 5; ++i) {
        cv::multiply(current, 1.000001, next);
        current = next;
    }

    current = src.clone();

    const int64 start = cv::getTickCount();

    for (int i = 0; i < loops; ++i) {
        cv::multiply(current, 1.000001, next);
        current = next;
    }

    const int64 end = cv::getTickCount();

    result = current.clone();

    return (end - start) * 1000.0 / cv::getTickFrequency();
}

static double run_gpu(const cv::Mat &src, int loops, cv::Mat &result)
{
    cv::ocl::setUseOpenCL(true);

    if (!cv::ocl::useOpenCL()) {
        std::cerr << "OpenCL could not be enabled." << std::endl;
        return -1.0;
    }

    cv::UMat current;
    cv::UMat next;

    src.copyTo(current);

    for (int i = 0; i < 5; ++i) {
        cv::multiply(current, 1.000001, next);
        current = next;
    }

    src.copyTo(current);
    cv::ocl::finish();

    const int64 start = cv::getTickCount();

    for (int i = 0; i < loops; ++i) {
        cv::multiply(current, 1.000001, next);
        current = next;
    }

    cv::ocl::finish();

    const int64 end = cv::getTickCount();

    current.copyTo(result);

    return (end - start) * 1000.0 / cv::getTickFrequency();
}

int main(int argc, char **argv)
{
    if (argc != 2) {
        std::cout << "Usage: " << argv[0] << " cpu|gpu|both" << std::endl;
        return 1;
    }

    const std::string mode = argv[1];
    const int loops = 500;

    cv::Mat src(2160, 3840, CV_32FC1);
    cv::randu(src, 0.0f, 1.0f);

    std::cout << "OpenCV version: " << CV_VERSION << std::endl;
    std::cout << "haveOpenCL: " << cv::ocl::haveOpenCL() << std::endl;
    std::cout << "Image size: 3840x2160, CV_32FC1" << std::endl;
    std::cout << "Loops: " << loops << std::endl;

    if (mode == "cpu") {
        cv::Mat cpu_result;
        const double cpu_ms = run_cpu(src, loops, cpu_result);

        std::cout << "Mode: CPU" << std::endl;
        std::cout << "CPU total time: " << cpu_ms << " ms" << std::endl;
        std::cout << "CPU average time: "
                  << cpu_ms / loops << " ms" << std::endl;
    }
    else if (mode == "gpu") {
        cv::ocl::Context context;

        if (!context.create(cv::ocl::Device::TYPE_GPU)) {
            std::cerr << "Failed to create GPU context." << std::endl;
            return 1;
        }

        cv::ocl::Device device = context.device(0);

        std::cout << "Mode: GPU" << std::endl;
        std::cout << "Device name: " << device.name() << std::endl;
        std::cout << "Vendor: " << device.vendorName() << std::endl;
        std::cout << "OpenCL version: " << device.version() << std::endl;

        cv::Mat gpu_result;
        const double gpu_ms = run_gpu(src, loops, gpu_result);

        if (gpu_ms < 0.0) {
            return 1;
        }

        std::cout << "GPU total time: " << gpu_ms << " ms" << std::endl;
        std::cout << "GPU average time: "
                  << gpu_ms / loops << " ms" << std::endl;
    }
    else if (mode == "both") {
        cv::Mat cpu_result;
        cv::Mat gpu_result;

        const double cpu_ms = run_cpu(src, loops, cpu_result);
        const double gpu_ms = run_gpu(src, loops, gpu_result);

        if (gpu_ms < 0.0) {
            return 1;
        }

        const double max_difference =
            cv::norm(cpu_result, gpu_result, cv::NORM_INF);

        std::cout << "Mode: BOTH" << std::endl;
        std::cout << "CPU average time: "
                  << cpu_ms / loops << " ms" << std::endl;
        std::cout << "GPU average time: "
                  << gpu_ms / loops << " ms" << std::endl;
        std::cout << "Speedup: "
                  << cpu_ms / gpu_ms << "x" << std::endl;
        std::cout << "Maximum result difference: "
                  << max_difference << std::endl;

        if (max_difference < 0.01) {
            std::cout << "Result check: PASS" << std::endl;
        } else {
            std::cout << "Result check: FAIL" << std::endl;
            return 1;
        }
    }
    else {
        std::cerr << "Invalid mode. Use cpu, gpu or both." << std::endl;
        return 1;
    }

    return 0;
}

The program mainly performs the following functions:

  • Creates a test image

  • Executes cv::multiply() on the CPU

  • Executes cv::multiply() on the GPU using UMat

  • Measures the average execution time of the CPU and GPU separately

  • Verifies that the CPU and GPU calculation results are consistent

  • Outputs the GPU acceleration ratio (Speedup)

Compile the Benchmark

Save the opencv_gpu_benchmark.cpp file created in VS Code to the ADB folder on the PC, and then push it to the development board:

adb push opencv_gpu_benchmark.cpp /data/local/tmp/

Enter the source directory:

cd /data/local/tmp

Compile:

g++ -O2 opencv_gpu_benchmark.cpp -o opencv_gpu_benchmark $(pkg-config --cflags --libs opencv4)

The executable file is generated:

opencv_gpu_benchmark

Run the Benchmark

export LD_LIBRARY_PATH=/opt/qcom/lib:$LD_LIBRARY_PATH 
./opencv_gpu_benchmark both

Running result:

OpenCV version: 4.10.0
haveOpenCL: 1
CPU average time: 28.9083 ms
GPU average time: 0.0474746 ms
Speedup: 608.92x
Maximum result difference: 0.000506639
Result check: PASS

Test Notes

In this test, the official Debian OpenCV GPU Benchmark achieved a GPU speedup of approximately 608.92×.

It should be noted that the test program uses only the OpenCV cv::multiply() operator for performance verification. This is a basic OpenCL functionality test with a relatively small computational workload. As a result, the GPU execution time is close to the timing precision of the benchmark, which causes the calculated speedup ratio to be significantly higher than expected.

Therefore, the Benchmark result is mainly used to verify that OpenCV can successfully invoke the GPU for OpenCL computation. The 608.92× result should not be regarded as an overall GPU performance metric.

Frequently Asked Questions

Device UI Lag or Frame Drops?

  • Check whether too many applications are running in the background and close unnecessary programs.

  • If the device is overheating, allow it to cool down. The operating frequency will automatically recover after the temperature decreases.

Screen Artifacts or Display Abnormalities?

  • Check whether the HDMI cable and display connections are secure.

  • Confirm that the screen or monitor resolution and refresh rate are configured correctly.

  • Try another cable or display to rule out hardware issues.

  • If a new LCD screen is being used, make sure its specifications and resolution are compatible with the device.

Large Games or 3D Applications Crash?

  • The device GPU is entry-level, and extremely demanding applications may exceed its performance capabilities.

  • Try lowering the graphics quality or resolution settings.

  • Ensure proper heat dissipation and avoid covering or blocking the device.

GPU Overheating or High Power Consumption?

  • Heat generation under high GPU load is normal. The system automatically reduces the operating frequency when necessary to provide thermal protection.

  • Check whether any applications are continuously using the GPU, such as background video playback or animations.