VirtualBox

Ignore:
Timestamp:
Jun 9, 2020 7:48:56 PM (5 years ago)
Author:
vboxsync
Message:

FE/Qt: experimental QOpenGLWidget (disabled). bugref:9695

Location:
trunk/src/VBox/Frontends/VirtualBox
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VirtualBox/Makefile.kmk

    r84696 r84746  
    215215else ifdef VBOX_GUI_USE_QGL
    216216 VirtualBoxVM_DEFS          += VBOX_GUI_USE_QGL
     217endif
     218ifdef VBOX_GUI_WITH_QTGLFRAMEBUFFER
     219 VirtualBoxVM_DEFS          += VBOX_GUI_WITH_QTGLFRAMEBUFFER
    217220endif
    218221ifdef VBOX_WITH_LIBCURL
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIFrameBuffer.cpp

    r84740 r84746  
    6464
    6565
     66#ifdef VBOX_GUI_WITH_QTGLFRAMEBUFFER
     67/* Experimental code. */
     68# ifdef RT_OS_LINUX
     69#include <GL/glx.h>
     70# endif
     71
     72/* Qt OpenGL includes: */
     73/* On Windows host they require the following two include files, otherwise compilation will fail with warnings.
     74 * The two files are already included, but they are needed if the Qt files are moved to the 'Qt includes:' section. */
     75// #include <iprt/stdint.h>
     76// #include <iprt/win/windows.h>
     77#include <QOffscreenSurface>
     78#include <QOpenGLFunctions>
     79#include <QOpenGLTexture>
     80#include <QOpenGLWidget>
     81
     82class UIFrameBufferPrivate;
     83class GLWidget;
     84
     85/* Handles the guest screen texture for the target GLWidget. */
     86class GLWidgetSource
     87{
     88public:
     89
     90    GLWidgetSource(GLWidget *pTarget);
     91    virtual ~GLWidgetSource();
     92
     93    GLWidget *Target() { return m_pTarget; }
     94
     95    virtual void initGuestScreenTexture(int w, int h) { RT_NOREF(w, h); };
     96    virtual void uninitGuestScreenTexture() {};
     97    virtual void updateGuestImage() {};
     98    virtual void cleanup() {};
     99    virtual bool IsHW() { return false; };
     100
     101private:
     102
     103    GLWidget *m_pTarget;
     104};
     105
     106/* Update the guest texture from a QImage. */
     107class GLWidgetSourceImage : public GLWidgetSource
     108{
     109public:
     110
     111    GLWidgetSourceImage(GLWidget *pTarget, QImage *pImage);
     112    virtual ~GLWidgetSourceImage();
     113
     114    virtual void initGuestScreenTexture(int w, int h);
     115    virtual void updateGuestImage();
     116
     117private:
     118
     119    QImage *m_pImage;
     120};
     121
     122# ifdef RT_OS_LINUX
     123/* The guest texture is a X pixmap. */
     124class GLWidgetSourcePixmap : public GLWidgetSource
     125{
     126public:
     127
     128    GLWidgetSourcePixmap(GLWidget *pTarget, Pixmap pixmap, VisualID visualid);
     129    virtual ~GLWidgetSourcePixmap();
     130
     131    virtual void initGuestScreenTexture(int w, int h);
     132    virtual void uninitGuestScreenTexture();
     133    virtual void cleanup();
     134    virtual bool IsHW() { return true; };
     135
     136private:
     137
     138    /* HW accelerated graphics output from a pixmap. */
     139    Pixmap m_Pixmap;
     140    VisualID m_visualid;
     141
     142    GLXPixmap m_glxPixmap;
     143
     144    Display *m_display;
     145    PFNGLXBINDTEXIMAGEEXTPROC m_pfnglXBindTexImageEXT;
     146    PFNGLXRELEASETEXIMAGEEXTPROC m_pfnglXReleaseTexImageEXT;
     147};
     148# endif /* RT_OS_LINUX */
     149
     150/* This widget allows to use OpenGL. */
     151class GLWidget : public QOpenGLWidget, protected QOpenGLFunctions
     152{
     153    Q_OBJECT
     154
     155public:
     156
     157    GLWidget(QWidget *parent, UIFrameBufferPrivate *pFramebuffer);
     158    virtual ~GLWidget();
     159
     160    /* Whether OpenGL is supported at all. */
     161    static bool isSupported();
     162
     163    void lock() { RTCritSectEnter(&m_critSect); }
     164    void unlock() { RTCritSectLeave(&m_critSect); }
     165
     166    /* Notification about the guest screen size. */
     167    void resizeGuestScreen(int w, int h);
     168    /* Which guest area is visible in the VM window. */
     169    void setGuestVisibleRect(int x, int y, int w, int h);
     170    /* Update the guest texture before painting. */
     171    void updateGuestImage();
     172
     173    /* The guest texture OpenGL target. */
     174    static GLenum const kTextureTarget = GL_TEXTURE_RECTANGLE;
     175
     176    /* The the guest screen source. */
     177    void setSource(GLWidgetSource *pSource, bool fForce);
     178
     179public slots:
     180
     181    void cleanup();
     182
     183protected:
     184
     185    /* QOpenGLWidget methods, which must be reimplemented. */
     186    void initializeGL() override;
     187    void paintGL() override;
     188    void resizeGL(int w, int h) override;
     189
     190private:
     191
     192    /* Get and possibly initialize the guest source. */
     193    GLWidgetSource *getSource();
     194
     195    /* Create the texture which contains the guest screen bitmap. */
     196    void createGuestTexture();
     197    /* Delete the texture which contains the guest screen bitmap. */
     198    void deleteGuestTexture();
     199
     200    /* Backlink. */
     201    UIFrameBufferPrivate *m_pFramebuffer;
     202
     203    /* Fallback when no guest screen is available. */
     204    GLWidgetSource m_nullSource;
     205    /* The current guest screen bitmap source. */
     206    GLWidgetSource *m_pSource;
     207
     208    /* The guest screen resolution. */
     209    QSize m_guestSize;
     210    /* The visible area of the guest screen in guest pixels. */
     211    QRect m_guestVisibleRect;
     212
     213    /** RTCRITSECT object to protect frame-buffer access. */
     214    RTCRITSECT m_critSect;
     215
     216    /* A new guest screen source has been set and needs reinitialization. */
     217    bool m_fReinitSource;
     218
     219    /* Texture which contains entire guest screen. Size is m_guestSize. */
     220    GLuint m_guestTexture;
     221};
     222#endif /* VBOX_GUI_WITH_QTGLFRAMEBUFFER */
     223
    66224/** IFramebuffer implementation used to maintain VM display video memory. */
    67225class ATL_NO_VTABLE UIFrameBufferPrivate : public QObject,
     
    242400
    243401    /** EMT callback: Notifies frame-buffer about 3D backend event.
    244       * @param        uType Event type. Currently only VBOX3D_NOTIFY_EVENT_TYPE_VISIBLE_3DDATA is supported.
     402      * @param        uType Event type. VBOX3D_NOTIFY_TYPE_*.
    245403      * @param        aData Event-specific data, depends on the supplied event type.
    246404      * @note         Any EMT callback is subsequent. No any other EMT callback can be called until this one processed.
     
    269427    virtual void doProcessVHWACommand(QEvent*) {}
    270428    /** Handles viewport resize-event. */
    271     virtual void viewportResized(QResizeEvent*) {}
     429    virtual void viewportResized(QResizeEvent*)
     430    {
     431# ifdef VBOX_GUI_WITH_QTGLFRAMEBUFFER
     432        /* Sync GL widget size with the MachineView widget: */
     433        /** @todo This can be probably done in a more automated way. */
     434        if (m_pGLWidget && m_pMachineView)
     435            m_pGLWidget->resize(m_pMachineView->viewport()->size());
     436# endif
     437    }
    272438    /** Handles viewport scroll-event. */
    273439    virtual void viewportScrolled(int, int) {}
    274440#endif /* VBOX_WITH_VIDEOHWACCEL */
     441
     442#ifdef VBOX_GUI_WITH_QTGLFRAMEBUFFER
     443    bool isGLWidgetSupported()
     444    {
     445        QString s = uiCommon().virtualBox().GetExtraData("GUI/GLWidget");
     446        return s == "1" && GLWidget::isSupported();
     447    }
     448#endif
    275449
    276450protected slots:
     
    386560    /** @} */
    387561
     562#ifdef VBOX_GUI_WITH_QTGLFRAMEBUFFER
     563    GLWidget *m_pGLWidget;
     564#endif
     565
    388566private:
    389567
     
    397575     QRect  m_cursorRectangle;
    398576};
     577
     578
     579#ifdef VBOX_GUI_WITH_QTGLFRAMEBUFFER
     580#define GLCHECK() \
     581do { \
     582    int glErr = glGetError(); \
     583    if (glErr != GL_NO_ERROR) LogRel4(("GUI GL 0x%x @%d\n", glErr, __LINE__)); \
     584} while(0)
     585
     586GLWidgetSource::GLWidgetSource(GLWidget *pTarget)
     587    : m_pTarget(pTarget)
     588{
     589}
     590
     591GLWidgetSource::~GLWidgetSource()
     592{
     593    cleanup();
     594}
     595
     596GLWidgetSourceImage::GLWidgetSourceImage(GLWidget *pTarget, QImage *pImage)
     597    : GLWidgetSource(pTarget)
     598    , m_pImage(pImage)
     599{
     600}
     601
     602GLWidgetSourceImage::~GLWidgetSourceImage()
     603{
     604}
     605
     606void GLWidgetSourceImage::initGuestScreenTexture(int w, int h)
     607{
     608    glTexImage2D(GLWidget::kTextureTarget, 0, GL_RGBA, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
     609    GLCHECK();
     610}
     611
     612void GLWidgetSourceImage::updateGuestImage()
     613{
     614    /* Copy the image content to the texture. */
     615    glTexSubImage2D(GLWidget::kTextureTarget, 0, 0, 0, m_pImage->width(), m_pImage->height(),
     616                    GL_BGRA, GL_UNSIGNED_BYTE, m_pImage->bits());
     617    GLCHECK();
     618}
     619
     620# ifdef RT_OS_LINUX
     621GLWidgetSourcePixmap::GLWidgetSourcePixmap(GLWidget *pTarget, Pixmap pixmap, VisualID visualid)
     622    : GLWidgetSource(pTarget)
     623    , m_Pixmap(pixmap)
     624    , m_visualid(visualid)
     625    , m_glxPixmap(0)
     626    , m_display(0)
     627    , m_pfnglXBindTexImageEXT(0)
     628    , m_pfnglXReleaseTexImageEXT(0)
     629{
     630}
     631
     632GLWidgetSourcePixmap::~GLWidgetSourcePixmap()
     633{
     634}
     635
     636void GLWidgetSourcePixmap::cleanup()
     637{
     638    m_pfnglXBindTexImageEXT = 0;
     639    m_pfnglXReleaseTexImageEXT = 0;
     640    m_Pixmap = 0;
     641    m_visualid = 0;
     642
     643    if (m_glxPixmap)
     644    {
     645        glXDestroyPixmap(m_display, m_glxPixmap);
     646        m_glxPixmap = 0;
     647    }
     648
     649    if (m_display)
     650    {
     651        XCloseDisplay(m_display);
     652        m_display = 0;
     653    }
     654}
     655
     656void GLWidgetSourcePixmap::initGuestScreenTexture(int w, int h)
     657{
     658    RT_NOREF(w, h);
     659
     660    LogRel4(("GUI: GLWidgetSourcePixmap::initGuestScreenTexture: Search for vid = %lu\n", m_visualid));
     661
     662    if (m_display)
     663        return; /* Already initialized. */
     664
     665    m_display = XOpenDisplay(0);
     666    if (m_display)
     667    {
     668        const char *glXExt = glXQueryExtensionsString(m_display, 0);
     669        if (glXExt && RTStrStr(glXExt, "GLX_EXT_texture_from_pixmap"))
     670        {
     671            m_pfnglXBindTexImageEXT = (PFNGLXBINDTEXIMAGEEXTPROC)glXGetProcAddress((const GLubyte *)"glXBindTexImageEXT");
     672            m_pfnglXReleaseTexImageEXT = (PFNGLXRELEASETEXIMAGEEXTPROC)glXGetProcAddress((const GLubyte *)"glXReleaseTexImageEXT");
     673            if (m_pfnglXBindTexImageEXT && m_pfnglXReleaseTexImageEXT)
     674            {
     675                LogRelMax(1, ("GUI: GLX_EXT_texture_from_pixmap supported\n"));
     676
     677                /* FBConfig attributes. */
     678                static int const aConfigAttribList[] =
     679                {
     680                    // GLX_RENDER_TYPE,                 GLX_RGBA_BIT,
     681                    // GLX_X_VISUAL_TYPE,               GLX_TRUE_COLOR,
     682                    // GLX_X_RENDERABLE,                True,                   // Render to GLX pixmaps
     683                    GLX_DRAWABLE_TYPE,               GLX_PIXMAP_BIT,         // Must support GLX pixmaps
     684                    GLX_BIND_TO_TEXTURE_RGBA_EXT,    True,                   // Must support GLX_EXT_texture_from_pixmap
     685                    GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_RECTANGLE_BIT_EXT, // Must support GL_TEXTURE_RECTANGLE for the frontend code
     686                    GLX_DOUBLEBUFFER,                False,                  // No need for double buffering for a pixmap.
     687                    GLX_RED_SIZE,                    8,                      // True color RGB with 8 bits per channel.
     688                    GLX_GREEN_SIZE,                  8,
     689                    GLX_BLUE_SIZE,                   8,
     690                    GLX_ALPHA_SIZE,                  8,
     691                    GLX_STENCIL_SIZE,                0,                      // No stencil buffer
     692                    GLX_DEPTH_SIZE,                  0,                      // No depth buffer
     693                    None
     694                };
     695
     696                /* Find a suitable FB config. */
     697                int cConfigs = 0;
     698                GLXFBConfig *paConfigs = glXChooseFBConfig(m_display, 0, aConfigAttribList, &cConfigs);
     699                LogRel4(("GUI: GLWidgetSourcePixmap::initGuestScreenTexture: paConfigs %p cConfigs %d\n", (void *)paConfigs, cConfigs));
     700                if (paConfigs)
     701                {
     702                    XVisualInfo *vi = NULL;
     703                    int i = 0;
     704                    for (; i < cConfigs; ++i)
     705                    {
     706                        /* Use XFree to free the data returned in the previous iteration of this loop. */
     707                        if (vi)
     708                            XFree(vi);
     709
     710                        vi = glXGetVisualFromFBConfig(m_display, paConfigs[i]);
     711                        if (!vi)
     712                            continue;
     713
     714                        LogRel4(("GUI: GLWidgetSourcePixmap::initGuestScreenTexture: %p vid %lu screen %d depth %d r %lu g %lu b %lu clrmap %d bitsperrgb %d\n",
     715                                 (void *)vi->visual, vi->visualid, vi->screen, vi->depth,
     716                                 vi->red_mask, vi->green_mask, vi->blue_mask, vi->colormap_size, vi->bits_per_rgb));
     717
     718                        if (vi->visualid != m_visualid)
     719                            continue;
     720
     721                        /* This FB config can be used. */
     722                        break;
     723                    }
     724
     725                    if (vi)
     726                    {
     727                        XFree(vi);
     728                        vi = 0;
     729                    }
     730
     731                    if (i < cConfigs)
     732                    {
     733                        /* Found the requested config. */
     734                        static int const aPixmapAttribList[] =
     735                        {
     736                            GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_RECTANGLE_EXT /* GLX_TEXTURE_2D_EXT */,
     737                            GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT,
     738                            None
     739                        };
     740                        m_glxPixmap = glXCreatePixmap(m_display, paConfigs[i], m_Pixmap, aPixmapAttribList);
     741                        LogRel4(("GUI: GLWidgetSourcePixmap::initGuestScreenTexture: m_glxPixmap %ld\n", m_glxPixmap));
     742
     743                        m_pfnglXBindTexImageEXT(m_display, m_glxPixmap, GLX_FRONT_LEFT_EXT, NULL);
     744
     745                        /* "Use XFree to free the memory returned by glXChooseFBConfig." */
     746                        XFree(paConfigs);
     747
     748                        /* Success. */
     749                        return;
     750                    }
     751
     752                    LogRel4(("GUI: GLWidgetSourcePixmap::initGuestScreenTexture: fbconfig not found\n"));
     753                    /* "Use XFree to free the memory returned by glXChooseFBConfig." */
     754                    XFree(paConfigs);
     755                }
     756            }
     757
     758            m_pfnglXBindTexImageEXT = 0;
     759            m_pfnglXReleaseTexImageEXT = 0;
     760        }
     761
     762        XCloseDisplay(m_display);
     763        m_display = 0;
     764    }
     765    else
     766    {
     767        LogRel4(("GUI: GLWidgetSourcePixmap::initGuestScreenTexture: failed to open Display\n"));
     768    }
     769}
     770
     771void GLWidgetSourcePixmap::uninitGuestScreenTexture()
     772{
     773    if (!m_glxPixmap)
     774        return;
     775
     776    AssertReturnVoid(m_display && m_pfnglXReleaseTexImageEXT);
     777    m_pfnglXReleaseTexImageEXT(m_display, m_glxPixmap, GLX_FRONT_LEFT_EXT);
     778}
     779# endif /* RT_OS_LINUX */
     780
     781GLWidget::GLWidget(QWidget *parent, UIFrameBufferPrivate *pFramebuffer)
     782    : QOpenGLWidget(parent)
     783    , m_pFramebuffer(pFramebuffer)
     784    , m_nullSource(this)
     785    , m_pSource(0)
     786    , m_fReinitSource(false)
     787    , m_guestTexture(0)
     788{
     789    int rc = RTCritSectInit(&m_critSect);
     790    AssertRC(rc);
     791
     792    setMouseTracking(true);
     793
     794#if 0
     795    QSurfaceFormat format;
     796    format.setVersion(3, 3);
     797    //format.setProfile(QSurfaceFormat::CoreProfile);
     798    format.setRenderableType(QSurfaceFormat::OpenGL);
     799    format.setRedBufferSize(8);
     800    format.setGreenBufferSize(8);
     801    format.setBlueBufferSize(8);
     802    format.setAlphaBufferSize(8);
     803    format.setDepthBufferSize(0);
     804    format.setStencilBufferSize(0);
     805    format.setSwapInterval(0);
     806    format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
     807    setFormat(format);
     808#endif
     809}
     810
     811GLWidget::~GLWidget()
     812{
     813    cleanup();
     814
     815    RTCritSectDelete(&m_critSect);
     816    RT_ZERO(m_critSect);
     817}
     818
     819/* Whether OpenGL is usable.
     820 * OpenGL 2.0 and support for GL_TEXTURE_RECTANGLE is required.
     821 */
     822/* static */ bool GLWidget::isSupported()
     823{
     824    /* Create an OpenGL conntext: */
     825    QOpenGLContext contextGL;
     826    contextGL.create();
     827    if (!contextGL.isValid())
     828        return false;
     829
     830    /* Create an offscreen surface: */
     831    QOffscreenSurface surface;
     832    surface.create();
     833    if (!surface.isValid())
     834        return false;
     835
     836    /* Make the OpenGL context current: */
     837    contextGL.makeCurrent(&surface);
     838
     839    /* Get the OpenGL version: */
     840    char const *pszVersion = (char const *)contextGL.functions()->glGetString(GL_VERSION);
     841    size_t cchVersion = pszVersion ? strlen(pszVersion) : 0;
     842
     843    int const verMajor = cchVersion >= 1 && '0' <= pszVersion[0] && pszVersion[0] <= '9'? pszVersion[0] - '0' : 0;
     844    int const verMinor = cchVersion >= 3 && '0' <= pszVersion[2] && pszVersion[2] <= '9'? pszVersion[2] - '0' : 0;
     845    int const ver = verMajor * 10 + verMinor;
     846
     847    /* Check if GL_TEXTURE_RECTANGLE is supported: */
     848    bool const fTextureRectangle = contextGL.hasExtension("GL_ARB_texture_rectangle")
     849                                || contextGL.hasExtension("GL_NV_texture_rectangle")
     850                                || ver >= 31;
     851
     852    /* Reset the current OpenGL context: */
     853    contextGL.doneCurrent();
     854
     855    /* Decide if OpenGL support is good enough: */
     856    return ver >= 20 && fTextureRectangle;
     857}
     858
     859/** @todo fForce is a bit of a hack. It does not allow to change the HW source to the QImage source,
     860 * when QImage source is automatically set during the guest screen resize. Think again!
     861 */
     862void GLWidget::setSource(GLWidgetSource *pSource, bool fForce)
     863{
     864    lock();
     865    if (   !fForce
     866        && m_pSource
     867        && m_pSource->IsHW())
     868    {
     869        LogRel4(("GUI: GLWidgetSourcePixmap::setSource: keeping HW source\n"));
     870        unlock();
     871        return;
     872    }
     873
     874    if (m_pSource)
     875        delete m_pSource;
     876
     877    m_pSource = pSource;
     878    m_fReinitSource = true;
     879    unlock();
     880}
     881
     882GLWidgetSource *GLWidget::getSource()
     883{
     884    Assert(RTCritSectIsOwner(&m_critSect));
     885    if (m_pSource)
     886    {
     887        if (m_fReinitSource)
     888        {
     889            m_fReinitSource = false;
     890            LogRel4(("GUI: GLWidgetSourcePixmap::getSource: recreate guest texture\n"));
     891
     892            /* If OpenGL context has been created: */
     893            if (context())
     894            {
     895                 /* Delete the current guest texture: */
     896                 deleteGuestTexture();
     897
     898                 /* Create and bind the new guest texture: */
     899                 createGuestTexture();
     900
     901                 glBindTexture(kTextureTarget, m_guestTexture); GLCHECK();
     902            }
     903        }
     904        return m_pSource;
     905    }
     906    return &m_nullSource;
     907}
     908
     909void GLWidget::resizeGuestScreen(int w, int h)
     910{
     911    /* The guest screen has been resized. Remember the size: */
     912    m_guestSize = QSize(w, h);
     913}
     914
     915void GLWidget::setGuestVisibleRect(int x, int y, int w, int h)
     916{
     917    /* Remember the area of the guest screen which must be displayed: */
     918    m_guestVisibleRect.setRect(x, y, w, h);
     919}
     920
     921void GLWidget::updateGuestImage()
     922{
     923    /* If OpenGL context has been created: */
     924    if (!context())
     925        return;
     926
     927    makeCurrent();
     928
     929    lock();
     930    GLWidgetSource *pSource = getSource();
     931    if (m_guestTexture)
     932    {
     933        /* Copy the image content to the texture. */
     934        glBindTexture(kTextureTarget, m_guestTexture);
     935        GLCHECK();
     936
     937        pSource->updateGuestImage();
     938    }
     939    unlock();
     940
     941    doneCurrent();
     942}
     943
     944void GLWidget::cleanup()
     945{
     946    if (!RTCritSectIsInitialized(&m_critSect))
     947        return;
     948
     949    /* If OpenGL context has been created: */
     950    if (!context())
     951        return;
     952
     953    makeCurrent();
     954
     955    lock();
     956    getSource()->cleanup();
     957    setSource(0, true);
     958    unlock();
     959
     960    /* Delete all OpenGL resources which are used by this widget: */
     961    deleteGuestTexture();
     962
     963    doneCurrent();
     964}
     965
     966void GLWidget::initializeGL()
     967{
     968    /* QOpenGLWidget documentation recommends to connect to the context's aboutToBeDestroyed() signal.
     969     * See https://doc.qt.io/qt-5/qopenglwidget.html#details
     970     * Connect the signal: */
     971    connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &GLWidget::cleanup);
     972
     973    /* Required initialization for QOpenGLFunctions: */
     974    initializeOpenGLFunctions();
     975
     976    /* Create OpenGL resources: */
     977    createGuestTexture();
     978
     979    /* Setup the OpenGL context state: */
     980    glClearColor(0, 0, 0, 1); GLCHECK();
     981    glDisable(GL_DEPTH_TEST); GLCHECK();
     982    glDisable(GL_CULL_FACE);  GLCHECK();
     983}
     984
     985void GLWidget::paintGL()
     986{
     987    lock();
     988    if (m_guestTexture)
     989    {
     990        /* Dimensions of the target window, i.e. the widget's dimensions. */
     991        GLint const w = width();
     992        GLint const h = height();
     993
     994        /* The guest coordinates of the visible guest screen area: */
     995        int x1 = m_guestVisibleRect.x();
     996        int y1 = m_guestVisibleRect.y();
     997        int x2 = x1 + m_guestVisibleRect.width();
     998        int y2 = y1 + m_guestVisibleRect.height();
     999
     1000        glDisable(GL_DEPTH_TEST); GLCHECK();
     1001        glDisable(GL_CULL_FACE); GLCHECK();
     1002
     1003        glEnable(kTextureTarget); GLCHECK();
     1004
     1005        /* Bind the guest texture: */
     1006        glBindTexture(kTextureTarget, m_guestTexture); GLCHECK();
     1007
     1008        /* This will reinitialize the source if necessary. */
     1009        getSource();
     1010
     1011        /* Draw the texture (upside down, because QImage and OpenGL store the bitmap differently): */
     1012        glBegin(GL_QUADS);
     1013        glTexCoord2i(x1, y1); glVertex2i(0, h);
     1014        glTexCoord2i(x1, y2); glVertex2i(0, 0);
     1015        glTexCoord2i(x2, y2); glVertex2i(w, 0);
     1016        glTexCoord2i(x2, y1); glVertex2i(w, h);
     1017        glEnd(); GLCHECK();
     1018
     1019        glBindTexture(kTextureTarget, 0); GLCHECK();
     1020
     1021        glDisable(kTextureTarget); GLCHECK();
     1022
     1023        glFlush(); GLCHECK();
     1024    }
     1025    unlock();
     1026}
     1027
     1028void GLWidget::resizeGL(int w, int h)
     1029{
     1030    /* Setup ModelViewProjection to work in the window cordinates: */
     1031    glMatrixMode(GL_MODELVIEW);
     1032    glLoadIdentity();
     1033    glOrtho(0, w, 0, h, -1, 1);
     1034    glMatrixMode(GL_PROJECTION);
     1035    glLoadIdentity();
     1036    GLCHECK();
     1037}
     1038
     1039void GLWidget::createGuestTexture()
     1040{
     1041    if (m_guestSize.isEmpty())
     1042        return;
     1043
     1044    /* Choose GL_NEAREST if no scaling or the scaling factor is an integer: */
     1045    double const scaleFactor = m_pFramebuffer->scaleFactor();
     1046    GLenum const filter = floor(scaleFactor) == scaleFactor ? GL_NEAREST : GL_LINEAR;
     1047
     1048    /* Create a new guest texture, which must be the same size as the guest screen: */
     1049    glGenTextures(1, &m_guestTexture);
     1050    glBindTexture(kTextureTarget, m_guestTexture);
     1051    glTexParameteri(kTextureTarget, GL_TEXTURE_MAG_FILTER, filter);
     1052    glTexParameteri(kTextureTarget, GL_TEXTURE_MIN_FILTER, filter);
     1053
     1054    lock();
     1055    getSource()->initGuestScreenTexture(m_guestSize.width(), m_guestSize.height());
     1056    unlock();
     1057
     1058    glBindTexture(kTextureTarget, 0);
     1059    GLCHECK();
     1060}
     1061
     1062void GLWidget::deleteGuestTexture()
     1063{
     1064    if (m_guestTexture)
     1065    {
     1066        glBindTexture(kTextureTarget, m_guestTexture);
     1067
     1068        lock();
     1069        getSource()->uninitGuestScreenTexture();
     1070        unlock();
     1071
     1072        glBindTexture(kTextureTarget, 0); GLCHECK();
     1073        glDeleteTextures(1, &m_guestTexture); GLCHECK();
     1074        m_guestTexture = 0;
     1075    }
     1076}
     1077#endif /* VBOX_GUI_WITH_QTGLFRAMEBUFFER */
    3991078
    4001079
     
    5381217    , m_dDevicePixelRatioActual(1.0)
    5391218    , m_fUseUnscaledHiDPIOutput(false)
     1219#ifdef VBOX_GUI_WITH_QTGLFRAMEBUFFER
     1220    , m_pGLWidget(0)
     1221#endif
    5401222{
    5411223    /* Update coordinate-system: */
     
    5721254        prepareConnections();
    5731255
     1256#ifdef VBOX_GUI_WITH_QTGLFRAMEBUFFER
     1257    /* Decide if we are going to use GL to draw the guest screen: */
     1258    if (isGLWidgetSupported())
     1259        m_pGLWidget = new GLWidget(m_pMachineView->viewport(), this);
     1260#endif
     1261
    5741262    /* Resize/rescale frame-buffer to the default size: */
    5751263    performResize(640, 480);
     
    6131301    if (m_pMachineView)
    6141302        prepareConnections();
     1303
     1304#ifdef VBOX_GUI_WITH_QTGLFRAMEBUFFER
     1305    /* Decide if we are going to use GL to draw the guest screen: */
     1306    m_pGLWidget = 0;
     1307    if (m_pMachineView && isGLWidgetSupported())
     1308        m_pGLWidget = new GLWidget(m_pMachineView->viewport(), this);
     1309#endif
    6151310}
    6161311
     
    10671762        }
    10681763
     1764#if defined(VBOX_GUI_WITH_QTGLFRAMEBUFFER) && defined(RT_OS_LINUX)
     1765        case VBOX3D_NOTIFY_TYPE_HW_SCREEN_CREATED:
     1766        case VBOX3D_NOTIFY_TYPE_HW_SCREEN_DESTROYED:
     1767        case VBOX3D_NOTIFY_TYPE_HW_SCREEN_UPDATE_BEGIN:
     1768        case VBOX3D_NOTIFY_TYPE_HW_SCREEN_UPDATE_END:
     1769        {
     1770            HRESULT hr = S_OK;
     1771            com::SafeArray<BYTE> notifyData(ComSafeArrayInArg(data));
     1772            if (m_pGLWidget)
     1773            {
     1774                if (uType == VBOX3D_NOTIFY_TYPE_HW_SCREEN_CREATED)
     1775                {
     1776                    LogRel4(("GUI: Notify3DEvent VBOX3D_NOTIFY_TYPE_3D_SCREEN_CREATED\n"));
     1777
     1778                    struct NotifyData
     1779                    {
     1780                        uint64_t u64NativeHandle;
     1781                        VisualID visualid;
     1782                    };
     1783                    struct NotifyData *pData = (struct NotifyData *)notifyData.raw();
     1784
     1785                    GLWidgetSource *p = new GLWidgetSourcePixmap(m_pGLWidget, (Pixmap)pData->u64NativeHandle, pData->visualid);
     1786                    m_pGLWidget->setSource(p, true);
     1787
     1788                    LogRelMax(1, ("GUI: Created a HW accelerated screen\n"));
     1789                }
     1790                else if (uType == VBOX3D_NOTIFY_TYPE_HW_SCREEN_DESTROYED)
     1791                {
     1792                    LogRel4(("GUI: Notify3DEvent VBOX3D_NOTIFY_TYPE_3D_SCREEN_DESTROYED\n"));
     1793
     1794                    GLWidgetSource *p = new GLWidgetSourceImage(m_pGLWidget, &m_image);
     1795                    m_pGLWidget->setSource(p, true);
     1796                }
     1797                else if (uType == VBOX3D_NOTIFY_TYPE_HW_SCREEN_UPDATE_BEGIN)
     1798                {
     1799                    /* Do nothing. */
     1800                }
     1801                else if (uType == VBOX3D_NOTIFY_TYPE_HW_SCREEN_UPDATE_END)
     1802                {
     1803                    struct NotifyData
     1804                    {
     1805                        uint64_t u64NativeHandle;
     1806                        int32_t left;
     1807                        int32_t top;
     1808                        int32_t right;
     1809                        int32_t bottom;
     1810                    };
     1811                    struct NotifyData *pData = (struct NotifyData *)notifyData.raw();
     1812
     1813                    /* Send the screen update message. */
     1814                    int iX = pData->left;
     1815                    int iY = pData->top;
     1816                    int iWidth = pData->right - pData->left;
     1817                    int iHeight = pData->bottom - pData->top;
     1818                    emit sigNotifyUpdate(iX, iY, iWidth, iHeight);
     1819                }
     1820            }
     1821            else
     1822            {
     1823                hr = E_FAIL; // Not supported
     1824            }
     1825            unlock();
     1826            return hr;
     1827        }
     1828#endif /* defined(VBOX_GUI_WITH_QTGLFRAMEBUFFER) && defined(RT_OS_LINUX) */
     1829
    10691830        default:
    10701831            break;
     
    12482009    }
    12492010
     2011#ifdef VBOX_GUI_WITH_QTGLFRAMEBUFFER
     2012   if (m_pGLWidget)
     2013   {
     2014       m_pGLWidget->resizeGuestScreen(m_iWidth, m_iHeight);
     2015
     2016       GLWidgetSource *p = new GLWidgetSourceImage(m_pGLWidget, &m_image);
     2017       m_pGLWidget->setSource(p, false);
     2018   }
     2019#endif
     2020
    12502021    lock();
    12512022
     
    14142185    if (m_image.isNull())
    14152186        return;
     2187
     2188#ifdef VBOX_GUI_WITH_QTGLFRAMEBUFFER
     2189    if (m_pGLWidget)
     2190    {
     2191        /* Draw the actually visible guest rectangle on the entire GLWidget.
     2192         * This code covers non-HiDPI normal and scaled modes. Scrollbars work too. */
     2193
     2194        /** @todo HiDPI support. Possibly need to split the geometry calculations from the QImage handling below
     2195         *        and share the geometry code with the OpenGL code path. */
     2196
     2197        /* Set the visible guest rectangle: */
     2198        m_pGLWidget->setGuestVisibleRect(m_pMachineView->contentsX(), m_pMachineView->contentsY(),
     2199                                         convertHostXTo(m_pGLWidget->width()), convertHostYTo(m_pGLWidget->height()));
     2200
     2201        /* Tell the GL Widget to update the guest screen content from the source: */
     2202        m_pGLWidget->updateGuestImage();
     2203
     2204        /* Redraw: */
     2205        m_pGLWidget->update();
     2206
     2207        /* Done: */
     2208        return;
     2209    }
     2210#endif /* VBOX_GUI_WITH_QTGLFRAMEBUFFER */
    14162211
    14172212    /* First we take the cached image as the source: */
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette