Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Why the opengl painting is blur on High DPI display
Forum Updated to NodeBB v4.3 + New Features

Why the opengl painting is blur on High DPI display

Scheduled Pinned Locked Moved Unsolved General and Desktop
3 Posts 3 Posters 154 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • B Offline
    B Offline
    BernardZhu
    wrote on last edited by
    #1

    Screenshot 2025-05-09 225508.png
    As the picture showes the text and the lines are very blur, this is on a windows systemc 4K display with 200% system scale
    I a using qt6.8. Thank.
    it can be reproduced by bleow code:

    #include <QApplication>
    #include <QWidget>
    #include <QPainter>
    #include <QOpenGLContext>
    #include <QOpenGLFunctions>
    #include <QOpenGLFramebufferObject>
    #include <QOpenGLPaintDevice>
    #include <QSurfaceFormat>
    #include <QOffscreenSurface>
    #include <QWindow>
    #include <QResizeEvent>
    #include <QDebug>
    
    class FBOWidget : public QWidget
    {
    public:
        FBOWidget(QWidget *parent = nullptr) : QWidget(parent), m_fbo(nullptr), m_context(nullptr), m_surface(nullptr), m_fboImage(nullptr)
        {
            // Don't use WA_PaintOnScreen as we want to use QPainter
            setAttribute(Qt::WA_NoSystemBackground);
            setAutoFillBackground(false);
            
            // Set up OpenGL context
            m_context = new QOpenGLContext(this);
            QSurfaceFormat format;
            format.setRenderableType(QSurfaceFormat::OpenGL);
            format.setVersion(3, 3);  // Use OpenGL 3.3 Core
            format.setProfile(QSurfaceFormat::CoreProfile);
            m_context->setFormat(format);
            
            if (!m_context->create()) {
                qCritical() << "Failed to create OpenGL context";
                return;
            }
            
            // Create offscreen surface for the OpenGL context
            m_surface = new QOffscreenSurface();
            m_surface->setFormat(m_context->format());
            m_surface->create();
            
            if (!m_surface->isValid()) {
                qCritical() << "Failed to create offscreen surface";
                return;
            }
            
            // Set a reasonable minimum size
            resize(400, 400);
        }
        
        ~FBOWidget()
        {
            // Clean up OpenGL resources
            if (m_context && m_surface && m_context->makeCurrent(m_surface)) {
                delete m_fbo;
                m_context->doneCurrent();
            }
            delete m_fboImage;
            delete m_context;
            delete m_surface;
        }
        
    protected:
        void resizeEvent(QResizeEvent *event) override
        {
            // Recreate FBO on resize
            if (m_context && m_surface && m_context->makeCurrent(m_surface)) {
                delete m_fbo;
                m_fbo = new QOpenGLFramebufferObject(size(), QOpenGLFramebufferObject::NoAttachment);
                
                // Make sure to update the image next time we paint
                delete m_fboImage;
                m_fboImage = nullptr;
                
                m_context->doneCurrent();
            }
            QWidget::resizeEvent(event);
        }
        
        void paintEvent(QPaintEvent *event) override
        {
            Q_UNUSED(event);
            
            if (!m_context || !m_surface)
                return;
            
            // Initialize FBO if it doesn't exist yet
            if (!m_fbo && m_context->makeCurrent(m_surface)) {
                m_fbo = new QOpenGLFramebufferObject(size(), QOpenGLFramebufferObject::NoAttachment);
                m_context->doneCurrent();
            }
            
            if (!m_fbo)
                return;
            
            // Only render to FBO if we need to update the image
            if (!m_fboImage) {
                if (m_context->makeCurrent(m_surface)) {
                    QOpenGLFunctions *f = m_context->functions();
                    
                    // Bind FBO
                    m_fbo->bind();
                    
                    // Clear with a background color
                    f->glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
                    f->glClear(GL_COLOR_BUFFER_BIT);
                    
                    // Draw using QPainter on the OpenGL paint device
                    {
                        // Create a paint device for the FBO
                        QOpenGLPaintDevice device(m_fbo->size());
    
                        // Create painter for the device
                        QPainter painter(&device);
                        painter.setRenderHint(QPainter::Antialiasing);
                        
                        // Set font for text
                        QFont font("Arial", 16, QFont::Bold);
                        painter.setFont(font);
                        
                        // Calculate positions
                        int radius = qMin(width(), height()) / 3;
                        QPoint center(width() / 2, height() / 2);
                        
                        // Draw text above the circle
                        painter.setPen(Qt::white);
                        QString text = "Qt6 FBO Demo";
                        QFontMetrics fm(font);
                        int textWidth = fm.horizontalAdvance(text);
                        int textHeight = fm.height();
                        painter.drawText(
                            center.x() - textWidth / 2,
                            center.y() - radius - textHeight,
                            text
                        );
                        
                        // Draw a circle in the center
                        // Circle already calculated above
                        painter.setPen(Qt::NoPen);
                        painter.setBrush(QColor(0, 120, 215));
                        painter.drawEllipse(center, radius, radius);
                        
                        // End painting on OpenGL device
                        painter.end();
                    }
                    
                    // Release FBO
                    m_fbo->release();
                    
                    // Store the rendered image
                    delete m_fboImage;
                    m_fboImage = new QImage(m_fbo->toImage());
                    
                    m_context->doneCurrent();
                }
            }
            
            // Now draw the stored image to the widget using regular QPainter
            if (m_fboImage) {
                QPainter widgetPainter(this);
                widgetPainter.drawImage(0, 0, *m_fboImage);
            }
        }
        
    private:
        QOpenGLFramebufferObject *m_fbo;
        QOpenGLContext *m_context;
        QOffscreenSurface *m_surface;
        QImage *m_fboImage;   // Cache the rendered image
    };
    
    int main(int argc, char *argv[])
    {
        QApplication app(argc, argv);
        
        // Set default surface format for the application
        QSurfaceFormat format;
        format.setRenderableType(QSurfaceFormat::OpenGL);
        format.setVersion(3, 3);
        format.setProfile(QSurfaceFormat::CoreProfile);
        format.setSamples(16);
        QSurfaceFormat::setDefaultFormat(format);
        
        FBOWidget widget;
        widget.setWindowTitle("Qt6 FBO Demo");
        widget.show();
        
        return app.exec();
    }
    
    

    cmake_minimum_required(VERSION 3.16)
    project(qt6_fbo_demo LANGUAGES CXX)

    set(CMAKE_CXX_STANDARD 17)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)

    Set the path to Qt6

    set(CMAKE_PREFIX_PATH "${CMAKE_PREFIX_PATH};${HOME}/qt/6.8.0/macos/lib/cmake")

    Find required Qt packages

    find_package(Qt6 REQUIRED COMPONENTS Core Widgets OpenGL OpenGLWidgets)

    Set automatic moc, uic, and rcc processing

    set(CMAKE_AUTOMOC ON)
    set(CMAKE_AUTORCC ON)
    set(CMAKE_AUTOUIC ON)

    Add executable

    add_executable(${PROJECT_NAME} main.cpp)

    Link Qt libraries

    target_link_libraries(${PROJECT_NAME} PRIVATE
    Qt6::Core
    Qt6::Widgets
    Qt6::OpenGL
    Qt6::OpenGLWidgets
    )

    OS X specific settings

    if(APPLE)
    set_target_properties(${PROJECT_NAME} PROPERTIES
    MACOSX_BUNDLE TRUE
    )
    endif()

    1 Reply Last reply
    0
    • JoeCFDJ Offline
      JoeCFDJ Offline
      JoeCFD
      wrote on last edited by JoeCFD
      #2

      You may need to add the following settings:

          // Enable High-DPI scaling (MUST be set before QApplication)
          QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);  // Auto-scaling
          QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);     // Sharp icons/images
      
          QApplication app(argc, argv);
      

      Your code works just fine on regular screens.

      1 Reply Last reply
      0
      • S Offline
        S Offline
        SamiV123
        wrote on last edited by SamiV123
        #3

        It's because your application is not hiDPI aware and windows does scaling by simply upscaling the bitmap that your application rendered in the window's back buffer before compositing.

        1 Reply Last reply
        0

        • Login

        • Login or register to search.
        • First post
          Last post
        0
        • Categories
        • Recent
        • Tags
        • Popular
        • Users
        • Groups
        • Search
        • Get Qt Extensions
        • Unsolved