Changeset 84746 in vbox for trunk/src/VBox/Frontends/VirtualBox
- Timestamp:
- Jun 9, 2020 7:48:56 PM (5 years ago)
- Location:
- trunk/src/VBox/Frontends/VirtualBox
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VirtualBox/Makefile.kmk
r84696 r84746 215 215 else ifdef VBOX_GUI_USE_QGL 216 216 VirtualBoxVM_DEFS += VBOX_GUI_USE_QGL 217 endif 218 ifdef VBOX_GUI_WITH_QTGLFRAMEBUFFER 219 VirtualBoxVM_DEFS += VBOX_GUI_WITH_QTGLFRAMEBUFFER 217 220 endif 218 221 ifdef VBOX_WITH_LIBCURL -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIFrameBuffer.cpp
r84740 r84746 64 64 65 65 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 82 class UIFrameBufferPrivate; 83 class GLWidget; 84 85 /* Handles the guest screen texture for the target GLWidget. */ 86 class GLWidgetSource 87 { 88 public: 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 101 private: 102 103 GLWidget *m_pTarget; 104 }; 105 106 /* Update the guest texture from a QImage. */ 107 class GLWidgetSourceImage : public GLWidgetSource 108 { 109 public: 110 111 GLWidgetSourceImage(GLWidget *pTarget, QImage *pImage); 112 virtual ~GLWidgetSourceImage(); 113 114 virtual void initGuestScreenTexture(int w, int h); 115 virtual void updateGuestImage(); 116 117 private: 118 119 QImage *m_pImage; 120 }; 121 122 # ifdef RT_OS_LINUX 123 /* The guest texture is a X pixmap. */ 124 class GLWidgetSourcePixmap : public GLWidgetSource 125 { 126 public: 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 136 private: 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. */ 151 class GLWidget : public QOpenGLWidget, protected QOpenGLFunctions 152 { 153 Q_OBJECT 154 155 public: 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 179 public slots: 180 181 void cleanup(); 182 183 protected: 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 190 private: 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 66 224 /** IFramebuffer implementation used to maintain VM display video memory. */ 67 225 class ATL_NO_VTABLE UIFrameBufferPrivate : public QObject, … … 242 400 243 401 /** 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_*. 245 403 * @param aData Event-specific data, depends on the supplied event type. 246 404 * @note Any EMT callback is subsequent. No any other EMT callback can be called until this one processed. … … 269 427 virtual void doProcessVHWACommand(QEvent*) {} 270 428 /** 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 } 272 438 /** Handles viewport scroll-event. */ 273 439 virtual void viewportScrolled(int, int) {} 274 440 #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 275 449 276 450 protected slots: … … 386 560 /** @} */ 387 561 562 #ifdef VBOX_GUI_WITH_QTGLFRAMEBUFFER 563 GLWidget *m_pGLWidget; 564 #endif 565 388 566 private: 389 567 … … 397 575 QRect m_cursorRectangle; 398 576 }; 577 578 579 #ifdef VBOX_GUI_WITH_QTGLFRAMEBUFFER 580 #define GLCHECK() \ 581 do { \ 582 int glErr = glGetError(); \ 583 if (glErr != GL_NO_ERROR) LogRel4(("GUI GL 0x%x @%d\n", glErr, __LINE__)); \ 584 } while(0) 585 586 GLWidgetSource::GLWidgetSource(GLWidget *pTarget) 587 : m_pTarget(pTarget) 588 { 589 } 590 591 GLWidgetSource::~GLWidgetSource() 592 { 593 cleanup(); 594 } 595 596 GLWidgetSourceImage::GLWidgetSourceImage(GLWidget *pTarget, QImage *pImage) 597 : GLWidgetSource(pTarget) 598 , m_pImage(pImage) 599 { 600 } 601 602 GLWidgetSourceImage::~GLWidgetSourceImage() 603 { 604 } 605 606 void 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 612 void 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 621 GLWidgetSourcePixmap::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 632 GLWidgetSourcePixmap::~GLWidgetSourcePixmap() 633 { 634 } 635 636 void 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 656 void 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 771 void 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 781 GLWidget::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 811 GLWidget::~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 */ 862 void 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 882 GLWidgetSource *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 909 void 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 915 void 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 921 void 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 944 void 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 966 void 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 985 void 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 1028 void 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 1039 void 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 1062 void 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 */ 399 1078 400 1079 … … 538 1217 , m_dDevicePixelRatioActual(1.0) 539 1218 , m_fUseUnscaledHiDPIOutput(false) 1219 #ifdef VBOX_GUI_WITH_QTGLFRAMEBUFFER 1220 , m_pGLWidget(0) 1221 #endif 540 1222 { 541 1223 /* Update coordinate-system: */ … … 572 1254 prepareConnections(); 573 1255 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 574 1262 /* Resize/rescale frame-buffer to the default size: */ 575 1263 performResize(640, 480); … … 613 1301 if (m_pMachineView) 614 1302 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 615 1310 } 616 1311 … … 1067 1762 } 1068 1763 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 1069 1830 default: 1070 1831 break; … … 1248 2009 } 1249 2010 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 1250 2021 lock(); 1251 2022 … … 1414 2185 if (m_image.isNull()) 1415 2186 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 */ 1416 2211 1417 2212 /* First we take the cached image as the source: */
Note:
See TracChangeset
for help on using the changeset viewer.