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

Why the opengl painting is blur on High DPI display

Scheduled Pinned Locked Moved Unsolved General and Desktop
3 Posts 3 Posters 355 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