Click here to Skip to main content
15,881,281 members
Articles / Desktop Programming / QT
Article

Windows on Arm: Native Support for Qt Framework

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
26 Apr 2023CPOL7 min read 5.1K   7   2
This article shows you how to reduce the computation time of the x64 architecture by 40 percent by making simple changes.

This article is a sponsored article. Articles such as these are intended to provide you with information on products and services that we consider useful and of value to developers

The Qt Framework (Qt) provides modularized C++ library classes and application programming interfaces (APIs) to accelerate cross-platform application development. Qt enables you to develop maintainable, highly performant, and reusable code. Thanks to its widget toolkit, all apps created with Qt have a native-looking user interface (UI). Qt also provides development tools, including Qt Creator, a cross-platform integrated development environment (IDE).

Qt v6.2 now supports native development for Windows on Arm (WoA). To demonstrate the advantages of native development, this article shows you how to perform affine transformations on graphic images. The transformations demonstrate the performance boost the AArch64 architecture provides. They include image rotation, scaling, and shearing, which are commonly used by AI-powered machine vision systems. Then, this tutorial shows you how to reduce the computation time of the x64 architecture by 40 percent by making simple changes.

Qt Now Includes Native WoA Support

Qt is an application development framework for desktop, embedded, and mobile platforms.

Qt v6.2 now supports native development for WoA, so you can download the installers from the official website. Qt enables you to build your software for either x64 or AArch64 processor architectures. As a result, you can fully leverage device hardware to accelerate your graphical user interface (GUI)-based applications.

Benefits of Qt

Qt provides cross-platform app development, so you can use the same high-level APIs to create apps that run on desktop, mobile, and Internet of things (IoT) devices with zero or minimal platform-specific code. This means you can use it to target many platforms simultaneously.

You can also use Qt to create intelligent edge devices. As more complex AI models move to edge devices, the demand for the efficiency of those devices continues to increase. AArch64 provides high performance with low energy requirements, making it ideal for apps on edge devices. Moreover, AArch64 is now fully supported on Windows 11 by Arm64EC.

Image 1

Setting Up for Development

This tutorial uses the Windows Dev Kit 2023 (also called Project Volterra) for development. But you can also get a similar performance boost on Mac computers with Apple silicon chips running Windows 11 (for example, by using Parallels Desktop).

To begin development, go to the Qt Group download page, register for the Qt trial, and download Qt. Or if you do not want to register, go to the Qt for Open Source Development page and download from there.

In the Qt Setup window, select at least Qt version 6.2. This tutorial uses Qt 6.4:

Image 2

Note that Windows Dev Kit 2023 runs the full version of Windows 11, so the installation and development processes are the same as on a typical desktop. This means you don’t need to learn any new skills to develop apps for WoA.

After installation, open Qt Creator, click Examples, select Qt6, and type “affine” in the search box.

Image 3

If you are new to Qt Creator, consult the documentation for a quick introduction. Project files are on the left side, and double-clicking them opens them in the editor. The Run and Debug buttons are on the bottom left. Or you can press F5 to run and debug your project and Ctrl + R to run it without the debugger.

The list of examples should include one project: Affine Transformations.

Click it to make the source code available in Qt Creator. Now build and run the app.

After execution, the app should look like this:

Image 4

The app continuously transforms the image of Tux (Linux’s penguin character) by rotating, scaling, and shearing it. You can stop the animation by clicking Animate. It is active when the app runs inside the constructor of the XFormWidget.

Now you can modify this default behavior.

Developing the Application

To modify the Affine Transformations app, add one more button with a Run label. When you click this button, it invokes the custom runAnimation method. This method is responsible for executing affine transformations several times. This allows you to measure the performance of these operations when you build the app for x64 and AArch64 architectures.

As with any other C++ app, the application’s entry point is the main function, as defined in main.cpp. The main function initializes and displays XFormWidget, in xform.h and xform.cpp.

Start by changing the xform.h file (located inside the Header folder in the project tree on the left side). First, add one include directive to import the QElapsedTimer class, which you use to measure the code’s execution time:

C++
#ifndef XFORM_H
#define XFORM_H
 
#include "arthurwidgets.h"
 
#include <QBasicTimer>
#include <QPolygonF>
#include <QElapsedTimer>

Then, modify the declaration of the XFormView class by declaring the runAnimation method in the public slots section. You will associate this method with the click signal of the Run button:

C++
class XFormView : public ArthurFrame
{
// …
public slots:
    void setAnimation(bool animate);
    void runAnimation();
    void updateControlPoints(const QPolygonF &);
    void changeRotation(int rotation);
    void changeScale(int scale);
    void changeShear(int shear);
// …

Finally, declare an instance of the QElapsedTimer object in the private section of the xform.h header file:

C++
private:
    QPolygonF m_controlPoints{{250, 250}, {350, 250}};
    HoverPoints *m_hoverPoints;
    qreal m_rotation = 0;
    qreal m_scale = 1;
    qreal m_shear = 0;
    XFormType m_type = VectorType;
    QPixmap m_pixmap;
    QString m_text;
    QBasicTimer timer;
    QElapsedTimer elapsedTimer;

Now, you need to modify the source file (xform.cpp). Do this by adding a Run button, binding the runAnimation method with the click signal of that button, and disabling the invocation of the animateClick method of animateButton prevents the default animation from running when you launch the app.

Then, modify the XFormWidget constructor (the declaration of this class is after XFormView) with the bolded statements in the following code:

C++
XFormWidget::XFormWidget(QWidget *parent)
    : QWidget(parent), textEditor(new QLineEdit)
{
    setWindowTitle(tr("Affine Transformations"));
 
    //…
 
    QPushButton *whatsThisButton = new QPushButton(mainGroup);
    whatsThisButton->setText(tr("What's This?"));
    whatsThisButton->setCheckable(true);
 
    QPushButton *runAnimationButton = new QPushButton(mainGroup);
    runAnimationButton->setText(tr("Run"));
 
    // …    
 
    QVBoxLayout *mainGroupLayout = new QVBoxLayout(mainGroup);
    mainGroupLayout->addWidget(rotateGroup);
    mainGroupLayout->addWidget(scaleGroup);
    mainGroupLayout->addWidget(shearGroup);
    mainGroupLayout->addWidget(typeGroup);
    mainGroupLayout->addStretch(1);
    mainGroupLayout->addWidget(resetButton);
    mainGroupLayout->addWidget(animateButton);
    mainGroupLayout->addWidget(showSourceButton);
#if QT_CONFIG(opengl)
    mainGroupLayout->addWidget(enableOpenGLButton);
#endif
    mainGroupLayout->addWidget(whatsThisButton);
    mainGroupLayout->addWidget(runAnimationButton);
 
    // …
 
    connect(resetButton, &QPushButton::clicked, view, &XFormView::reset);
    connect(animateButton, &QPushButton::clicked, view, &XFormView::setAnimation);
    connect(whatsThisButton, &QPushButton::clicked, view, 
        &ArthurFrame::setDescriptionEnabled);
    connect(runAnimationButton, &QPushButton::clicked, view, &XFormView::runAnimation);
    connect(whatsThisButton, &QPushButton::clicked, view->hoverPoints(), 
        &HoverPoints::setDisabled);
    connect(view, &XFormView::descriptionEnabledChanged, view->hoverPoints(), 
        &HoverPoints::setDisabled);
    connect(view, &XFormView::descriptionEnabledChanged, whatsThisButton,
        &QPushButton::setChecked);
    connect(showSourceButton, &QPushButton::clicked, view, &XFormView::showSource);
#if QT_CONFIG(opengl)
    connect(enableOpenGLButton, &QPushButton::clicked, view, &XFormView::enableOpenGL);
#endif
    view->loadSourceFile(":res/affine/xform.cpp");
    view->loadDescription(":res/affine/xform.html");
 
    // defaults
    view->reset();
    vectorType->setChecked(true);   
    textEditor->setText("Qt Affine Transformation Example");
    textEditor->setEnabled(false);
 
    //animateButton->animateClick(); // Prevent running the default animation
}

Next, implement the runAnimation method:

C++
void XFormView::runAnimation()
{
    // Restart timer
    elapsedTimer.restart();
    // Run affine transformations 10,000 times
    for(int i = 0; i < 10000; i++) {
        QPointF center(m_hoverPoints->points().at(0));
        QTransform m;
        m.translate(center.x(), center.y());
        m.rotate(0.2);
        m.translate(-center.x(), -center.y());
        m_hoverPoints->setPoints(m_hoverPoints->points() * m);
 
        setUpdatesEnabled(false);
        static qreal scale_inc = 0.003;
        static qreal shear_inc = -0.001;
        emit scaleChanged(int((m_scale + scale_inc) * 1000));
        emit shearChanged(int((m_shear + shear_inc) * 1000));
        if (m_scale >= 4.0 || m_scale <= 0.1)
            scale_inc = -scale_inc;
        if (m_shear >= 1.0 || m_shear <= -1.0)
            shear_inc = -shear_inc;
        setUpdatesEnabled(true);
 
        m_hoverPoints->firePointChange();
    }
    // Measure performance
    qDebug() << "Animation took" << elapsedTimer.elapsed() << "milliseconds";
}

The method works like the original event handler for the Animate button. It translates (QTransform.translate), rotates (QTransform.rotate), scales (QTransform.scale), and shears (QTransform.shear) the image. It implements all these actions using the statements under the for loop. Under the hood, QTransform uses the transformation matrix to perform the affine transformation. So, you can also manually set elements of that matrix using the QTransform.setMatrix method.

Note that the user interface is updated using signals (via the emit keyword). This update performs the scale and shear changes.

Then, you only added three things:

  • elapsedTimer.restart method to restart an instance of the QElapsedTimer
  • Embedded transformations within a for loop
  • qDebug to print information about the code execution time in the Debugger console

All of the above was independent on the architecture. This means that you can use the same features when developing for AArch64 as you would for x64, including debugging. You can also use the provided CMakeLists.txt to configure CMake and add unit tests to the project.

Running the Application

Now it's time to run the application using the AArch64 build. To do so, use the icons in the bottom left corner of the QtCreator. Select Desktop Qt 6.4.2 MSVC2019 ARM64:

Image 5

Start debugging by clicking the green play icon:

Image 6

Click Run to trigger the animation. The Tux image is transformed 10,000 times. The time needed for the transformations appears in the Application Output window at the bottom of the Qt Creator window. Note that you must click Application Output or press Alt + 3 to view it:

Image 7

On average, the computation time is approximately 270 milliseconds when the app uses AArch64 architecture.

Now, switch to x64, rebuild, and launch the app. Click Run, and you will see the computation time for the x64 architecture:

Image 8

The computations are slower and take about 438 milliseconds on average. This means that your app performs 1.6 times faster on AArch64 than on x64.

Conclusion

The Qt Framework, beginning with version 6.2, supports native WoA development. This tutorial demonstrates the benefits of using Qt when building for AArch64 processors. Qt enables you to develop maintainable, highly performant, and reusable code, and its support for WoA allows your apps to perform much better. In this tutorial, the build on AArch64 was 1.6 times faster than x64.

You can take advantage of this performance boost by switching the build configuration in the Qt interface. Everything else stays the same. You can quickly accelerate your existing Qt applications and process application commands almost twice as fast. This boosts the performance of your AI-powered edge devices and improves their accuracy, allowing you to deploy more demanding AI models.

Try the Qt Framework on WoA for yourself, and use the Windows Dev Kit 2023 to compile and test your app.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
Dawid Borycki is a software engineer and biomedical researcher with extensive experience in Microsoft technologies. He has completed a broad range of challenging projects involving the development of software for device prototypes (mostly medical equipment), embedded device interfacing, and desktop and mobile programming. Borycki is an author of two Microsoft Press books: “Programming for Mixed Reality (2018)” and “Programming for the Internet of Things (2017).”

Comments and Discussions

 
QuestionNative vs. x86 emulation Pin
Victor Khokhlov1-May-23 22:04
Victor Khokhlov1-May-23 22:04 
Questionspeed increase on AArch64 Pin
Daniel Anderson 202127-Apr-23 18:41
Daniel Anderson 202127-Apr-23 18:41 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.