src/opengl/qgl_egl.cpp
changeset 30 5dc02b23752f
parent 18 2f34d5167611
child 33 3e2da88830cd
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
    38 ** $QT_END_LICENSE$
    38 ** $QT_END_LICENSE$
    39 **
    39 **
    40 ****************************************************************************/
    40 ****************************************************************************/
    41 
    41 
    42 #include <QtOpenGL/qgl.h>
    42 #include <QtOpenGL/qgl.h>
       
    43 #include <QtOpenGL/qglpixelbuffer.h>
    43 #include "qgl_p.h"
    44 #include "qgl_p.h"
    44 #include "qgl_egl_p.h"
    45 #include "qgl_egl_p.h"
       
    46 #include "qglpixelbuffer_p.h"
       
    47 
       
    48 #ifdef Q_WS_X11
       
    49 #include <QtGui/private/qpixmap_x11_p.h>
       
    50 #endif
    45 
    51 
    46 QT_BEGIN_NAMESPACE
    52 QT_BEGIN_NAMESPACE
    47 
    53 
    48 // Set device configuration attributes from a QGLFormat instance.
    54 void qt_eglproperties_set_glformat(QEglProperties& eglProperties, const QGLFormat& glFormat)
    49 void qt_egl_set_format(QEglProperties& props, int deviceType, const QGLFormat& f)
    55 {
    50 {
    56     int redSize     = glFormat.redBufferSize();
    51     if (deviceType == QInternal::Pixmap || deviceType == QInternal::Image)
    57     int greenSize   = glFormat.greenBufferSize();
    52         props.setValue(EGL_SURFACE_TYPE, EGL_PIXMAP_BIT);
    58     int blueSize    = glFormat.blueBufferSize();
    53     else if (deviceType == QInternal::Pbuffer)
    59     int alphaSize   = glFormat.alphaBufferSize();
    54         props.setValue(EGL_SURFACE_TYPE, EGL_PBUFFER_BIT);
    60     int depthSize   = glFormat.depthBufferSize();
    55     else
    61     int stencilSize = glFormat.stencilBufferSize();
    56         props.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT);
    62     int sampleCount = glFormat.samples();
    57 
    63 
    58     // Set the pixel format to that contained in the QGLFormat
    64     // QGLFormat uses a magic value of -1 to indicate "don't care", even when a buffer of that
    59     // if the system hasn't already chosen a fixed format to
    65     // type has been requested. So we must check QGLFormat's booleans too if size is -1:
    60     // match the pixmap, widget, etc.
    66     if (glFormat.alpha() && alphaSize <= 0)
    61     if (props.value(EGL_RED_SIZE) == 0 || f.redBufferSize() != -1)
    67         alphaSize = 1;
    62         props.setValue(EGL_RED_SIZE, f.redBufferSize() == -1 ? 1 : f.redBufferSize());
    68     if (glFormat.depth() && depthSize <= 0)
    63     if (props.value(EGL_GREEN_SIZE) == 0 || f.greenBufferSize() != -1)
    69         depthSize = 1;
    64         props.setValue(EGL_GREEN_SIZE, f.greenBufferSize() == -1 ? 1 : f.greenBufferSize());
    70     if (glFormat.stencil() && stencilSize <= 0)
    65     if (props.value(EGL_BLUE_SIZE) == 0 || f.blueBufferSize() != -1)
    71         stencilSize = 1;
    66         props.setValue(EGL_BLUE_SIZE, f.blueBufferSize() == -1 ? 1 : f.blueBufferSize());
    72     if (glFormat.sampleBuffers() && sampleCount <= 0)
    67     if (f.alpha()) {
    73         sampleCount = 1;
    68         if (props.value(EGL_ALPHA_SIZE) == 0 || f.alphaBufferSize() != -1)
    74 
    69             props.setValue(EGL_ALPHA_SIZE, f.alphaBufferSize() == -1 ? 1 : f.alphaBufferSize());
    75     // We want to make sure 16-bit configs are chosen over 32-bit configs as they will provide
    70     }
    76     // the best performance. The EGL config selection algorithm is a bit stange in this regard:
    71 
    77     // The selection criteria for EGL_BUFFER_SIZE is "AtLeast", so we can't use it to discard
    72     if (f.depth())
    78     // 32-bit configs completely from the selection. So it then comes to the sorting algorithm.
    73         props.setValue(EGL_DEPTH_SIZE, f.depthBufferSize() == -1 ? 1 : f.depthBufferSize());
    79     // The red/green/blue sizes have a sort priority of 3, so they are sorted by first. The sort
    74     if (f.stencil())
    80     // order is special and described as "by larger _total_ number of color bits.". So EGL will
    75         props.setValue(EGL_STENCIL_SIZE, f.stencilBufferSize() == -1 ? 1 : f.stencilBufferSize());
    81     // put 32-bit configs in the list before the 16-bit configs. However, the spec also goes on
    76     if (f.sampleBuffers()) {
    82     // to say "If the requested number of bits in attrib_list for a particular component is 0,
    77         props.setValue(EGL_SAMPLE_BUFFERS, 1);
    83     // then the number of bits for that component is not considered". This part of the spec also
    78         props.setValue(EGL_SAMPLES, f.samples() == -1 ? 1 : f.samples());
    84     // seems to imply that setting the red/green/blue bits to zero means none of the components
    79     } else {
    85     // are considered and EGL disregards the entire sorting rule. It then looks to the next
    80         props.setValue(EGL_SAMPLE_BUFFERS, 0);
    86     // highest priority rule, which is EGL_BUFFER_SIZE. Despite the selection criteria being
    81     }
    87     // "AtLeast" for EGL_BUFFER_SIZE, it's sort order is "smaller" meaning 16-bit configs are
    82     if (deviceType == QInternal::Widget)
    88     // put in the list before 32-bit configs. So, to make sure 16-bit is preffered over 32-bit,
    83         props.setValue(EGL_LEVEL, f.plane());
    89     // we must set the red/green/blue sizes to zero. This has an unfortunate consequence that
       
    90     // if the application sets the red/green/blue size to 5/6/5 on the QGLFormat, they will
       
    91     // probably get a 32-bit config, even when there's an RGB565 config avaliable. Oh well.
       
    92 
       
    93     // Now normalize the values so -1 becomes 0
       
    94     redSize   = redSize   > 0 ? redSize   : 0;
       
    95     greenSize = greenSize > 0 ? greenSize : 0;
       
    96     blueSize  = blueSize  > 0 ? blueSize  : 0;
       
    97     alphaSize = alphaSize > 0 ? alphaSize : 0;
       
    98     depthSize = depthSize > 0 ? depthSize : 0;
       
    99     stencilSize = stencilSize > 0 ? stencilSize : 0;
       
   100     sampleCount = sampleCount > 0 ? sampleCount : 0;
       
   101 
       
   102     eglProperties.setValue(EGL_RED_SIZE,   redSize);
       
   103     eglProperties.setValue(EGL_GREEN_SIZE, greenSize);
       
   104     eglProperties.setValue(EGL_BLUE_SIZE,  blueSize);
       
   105     eglProperties.setValue(EGL_ALPHA_SIZE, alphaSize);
       
   106     eglProperties.setValue(EGL_DEPTH_SIZE, depthSize);
       
   107     eglProperties.setValue(EGL_STENCIL_SIZE, stencilSize);
       
   108     eglProperties.setValue(EGL_SAMPLES, sampleCount);
       
   109     eglProperties.setValue(EGL_SAMPLE_BUFFERS, sampleCount ? 1 : 0);
    84 }
   110 }
    85 
   111 
    86 // Updates "format" with the parameters of the selected configuration.
   112 // Updates "format" with the parameters of the selected configuration.
    87 void qt_egl_update_format(const QEglContext& context, QGLFormat& format)
   113 void qt_glformat_from_eglconfig(QGLFormat& format, const EGLConfig config)
    88 {
   114 {
    89     EGLint value = 0;
   115     EGLint redSize     = 0;
    90 
   116     EGLint greenSize   = 0;
    91     if (context.configAttrib(EGL_RED_SIZE, &value))
   117     EGLint blueSize    = 0;
    92         format.setRedBufferSize(value);
   118     EGLint alphaSize   = 0;
    93     if (context.configAttrib(EGL_GREEN_SIZE, &value))
   119     EGLint depthSize   = 0;
    94         format.setGreenBufferSize(value);
   120     EGLint stencilSize = 0;
    95     if (context.configAttrib(EGL_BLUE_SIZE, &value))
   121     EGLint sampleCount = 0;
    96         format.setBlueBufferSize(value);
   122     EGLint level       = 0;
    97     if (context.configAttrib(EGL_ALPHA_SIZE, &value)) {
   123 
    98         format.setAlpha(value != 0);
   124     EGLDisplay display = QEgl::display();
    99         if (format.alpha())
   125     eglGetConfigAttrib(display, config, EGL_RED_SIZE,     &redSize);
   100             format.setAlphaBufferSize(value);
   126     eglGetConfigAttrib(display, config, EGL_GREEN_SIZE,   &greenSize);
   101     }
   127     eglGetConfigAttrib(display, config, EGL_BLUE_SIZE,    &blueSize);
   102 
   128     eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE,   &alphaSize);
   103     if (context.configAttrib(EGL_DEPTH_SIZE, &value)) {
   129     eglGetConfigAttrib(display, config, EGL_DEPTH_SIZE,   &depthSize);
   104         format.setDepth(value != 0);
   130     eglGetConfigAttrib(display, config, EGL_STENCIL_SIZE, &stencilSize);
   105         if (format.depth())
   131     eglGetConfigAttrib(display, config, EGL_SAMPLES,      &sampleCount);
   106             format.setDepthBufferSize(value);
   132     eglGetConfigAttrib(display, config, EGL_LEVEL,        &level);
   107     }
   133 
   108 
   134     format.setRedBufferSize(redSize);
   109     if (context.configAttrib(EGL_LEVEL, &value))
   135     format.setGreenBufferSize(greenSize);
   110         format.setPlane(value);
   136     format.setBlueBufferSize(blueSize);
   111 
   137     format.setAlphaBufferSize(alphaSize);
   112     if (context.configAttrib(EGL_SAMPLE_BUFFERS, &value)) {
   138     format.setDepthBufferSize(depthSize);
   113         format.setSampleBuffers(value != 0);
   139     format.setStencilBufferSize(stencilSize);
   114         if (format.sampleBuffers()) {
   140     format.setSamples(sampleCount);
   115             context.configAttrib(EGL_SAMPLES, &value);
   141     format.setPlane(level + 1);      // EGL calls level 0 "normal" whereas Qt calls 1 "normal"
   116             format.setSamples(value);
   142     format.setDirectRendering(true); // All EGL contexts are direct-rendered
   117         }
   143     format.setRgba(true);            // EGL doesn't support colour index rendering
   118     }
   144     format.setStereo(false);         // EGL doesn't support stereo buffers
   119 
   145     format.setAccumBufferSize(0);    // EGL doesn't support accululation buffers
   120     if (context.configAttrib(EGL_STENCIL_SIZE, &value)) {
       
   121         format.setStencil(value != 0);
       
   122         if (format.stencil())
       
   123             format.setStencilBufferSize(value);
       
   124     }
       
   125 
   146 
   126     // Clear the EGL error state because some of the above may
   147     // Clear the EGL error state because some of the above may
   127     // have errored out because the attribute is not applicable
   148     // have errored out because the attribute is not applicable
   128     // to the surface type.  Such errors don't matter.
   149     // to the surface type.  Such errors don't matter.
   129     context.clearError();
   150     eglGetError();
   130 }
   151 }
   131 
   152 
   132 bool QGLFormat::hasOpenGL()
   153 bool QGLFormat::hasOpenGL()
   133 {
   154 {
   134     return true;
   155     return true;
   139     Q_D(QGLContext);
   160     Q_D(QGLContext);
   140     if (!d->valid)
   161     if (!d->valid)
   141         return;
   162         return;
   142     d->cleanup();
   163     d->cleanup();
   143     doneCurrent();
   164     doneCurrent();
   144     if (d->eglContext) {
   165     if (d->eglContext && d->ownsEglContext) {
   145         d->destroyEglSurfaceForDevice();
   166         d->destroyEglSurfaceForDevice();
   146         delete d->eglContext;
   167         delete d->eglContext;
   147     }
   168     }
       
   169     d->ownsEglContext = false;
   148     d->eglContext = 0;
   170     d->eglContext = 0;
   149     d->eglSurface = EGL_NO_SURFACE;
   171     d->eglSurface = EGL_NO_SURFACE;
   150     d->crWin = false;
   172     d->crWin = false;
   151     d->sharing = false;
   173     d->sharing = false;
   152     d->valid = false;
   174     d->valid = false;
   156 }
   178 }
   157 
   179 
   158 void QGLContext::makeCurrent()
   180 void QGLContext::makeCurrent()
   159 {
   181 {
   160     Q_D(QGLContext);
   182     Q_D(QGLContext);
   161     if (!d->valid || !d->eglContext || d->eglSurface == EGL_NO_SURFACE) {
   183     if (!d->valid || !d->eglContext || d->eglSurfaceForDevice() == EGL_NO_SURFACE) {
   162         qWarning("QGLContext::makeCurrent(): Cannot make invalid context current");
   184         qWarning("QGLContext::makeCurrent(): Cannot make invalid context current");
   163         return;
   185         return;
   164     }
   186     }
   165 
   187 
   166     if (d->eglContext->makeCurrent(d->eglSurface))
   188     if (d->eglContext->makeCurrent(d->eglSurfaceForDevice())) {
   167         QGLContextPrivate::setCurrentContext(this);
   189         QGLContextPrivate::setCurrentContext(this);
       
   190         if (!d->workaroundsCached) {
       
   191             d->workaroundsCached = true;
       
   192             const char *renderer = reinterpret_cast<const char *>(glGetString(GL_RENDERER));
       
   193             if (strstr(renderer, "SGX") || strstr(renderer, "MBX")) {
       
   194                 // PowerVR MBX/SGX chips needs to clear all buffers when starting to render
       
   195                 // a new frame, otherwise there will be a performance penalty to pay for
       
   196                 // each frame.
       
   197                 d->workaround_needsFullClearOnEveryFrame = true;
       
   198 
       
   199                 // Older PowerVR SGX drivers (like the one in the N900) have a
       
   200                 // bug which prevents glCopyTexSubImage2D() to work with a POT
       
   201                 // or GL_ALPHA texture bound to an FBO. The only way to
       
   202                 // identify that driver is to check the EGL version number for it.
       
   203                 if (strstr(eglQueryString(d->eglContext->display(), EGL_VERSION), "1.3"))
       
   204                     d->workaround_brokenFBOReadBack = true;
       
   205             }
       
   206         }
       
   207     }
   168 }
   208 }
   169 
   209 
   170 void QGLContext::doneCurrent()
   210 void QGLContext::doneCurrent()
   171 {
   211 {
   172     Q_D(QGLContext);
   212     Q_D(QGLContext);
   181 {
   221 {
   182     Q_D(const QGLContext);
   222     Q_D(const QGLContext);
   183     if (!d->valid || !d->eglContext)
   223     if (!d->valid || !d->eglContext)
   184         return;
   224         return;
   185 
   225 
   186     d->eglContext->swapBuffers(d->eglSurface);
   226     d->eglContext->swapBuffers(d->eglSurfaceForDevice());
   187 }
   227 }
   188 
   228 
   189 void QGLContextPrivate::destroyEglSurfaceForDevice()
   229 void QGLContextPrivate::destroyEglSurfaceForDevice()
   190 {
   230 {
   191     if (eglSurface != EGL_NO_SURFACE) {
   231     if (eglSurface != EGL_NO_SURFACE) {
   192 #ifdef Q_WS_X11
   232 #ifdef Q_WS_X11
   193         // Make sure we don't call eglDestroySurface on a surface which
   233         // Make sure we don't call eglDestroySurface on a surface which
   194         // was created for a different winId:
   234         // was created for a different winId:
   195         if (paintDevice->devType() == QInternal::Widget) {
   235         if (paintDevice && paintDevice->devType() == QInternal::Widget) {
   196             QGLWidget* w = static_cast<QGLWidget*>(paintDevice);
   236             QGLWidget* w = static_cast<QGLWidget*>(paintDevice);
   197 
   237 
   198             if (w->d_func()->eglSurfaceWindowId == w->winId())
   238             if (w->d_func()->eglSurfaceWindowId == w->winId())
   199                 eglDestroySurface(eglContext->display(), eglSurface);
   239                 eglDestroySurface(eglContext->display(), eglSurface);
   200             else
   240             else
   204             eglDestroySurface(eglContext->display(), eglSurface);
   244             eglDestroySurface(eglContext->display(), eglSurface);
   205         eglSurface = EGL_NO_SURFACE;
   245         eglSurface = EGL_NO_SURFACE;
   206     }
   246     }
   207 }
   247 }
   208 
   248 
       
   249 EGLSurface QGLContextPrivate::eglSurfaceForDevice() const
       
   250 {
       
   251     // If a QPixmapData had to create the QGLContext, we don't have a paintDevice
       
   252     if (!paintDevice)
       
   253         return eglSurface;
       
   254 
       
   255 #ifdef Q_WS_X11
       
   256     if (paintDevice->devType() == QInternal::Pixmap) {
       
   257         QPixmapData *pmd = static_cast<QPixmap*>(paintDevice)->data_ptr().data();
       
   258         if (pmd->classId() == QPixmapData::X11Class) {
       
   259             QX11PixmapData* x11PixmapData = static_cast<QX11PixmapData*>(pmd);
       
   260             return (EGLSurface)x11PixmapData->gl_surface;
       
   261         }
       
   262     }
       
   263 #endif
       
   264 
       
   265     if (paintDevice->devType() == QInternal::Pbuffer) {
       
   266         QGLPixelBuffer* pbuf = static_cast<QGLPixelBuffer*>(paintDevice);
       
   267         return pbuf->d_func()->pbuf;
       
   268     }
       
   269 
       
   270     return eglSurface;
       
   271 }
       
   272 
   209 void QGLWidget::setMouseTracking(bool enable)
   273 void QGLWidget::setMouseTracking(bool enable)
   210 {
   274 {
   211     QWidget::setMouseTracking(enable);
   275     QWidget::setMouseTracking(enable);
   212 }
   276 }
   213 
   277