Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-56234

OpenGL glVertexAttribArray API usage error in Qt5Guid.dll

    XMLWordPrintable

Details

    • Bug
    • Resolution: Duplicate
    • P1: Critical
    • None
    • 5.7.0
    • GUI: OpenGL
    • None

    Description

      Upload test app source code to demonstrate the issues, there are three Qt OpenGL issues in this test app.

      Test app runs on PC + Windows 10, the logic of this app is quite simple, QT draws some 2D widget (fonts, buttons, spin boxes, text boxes, etc), then QT render the 2D window to a texture,
      and then call glReadPixel to read the texture back and dump as an BMP file named test.bmp. (please don’t care about the abnormal of the window present, just focus on the result picture test.bmp),
      Using Nvidia card, you will see the correct test.bmp, but with AMD card, you will get nothing since there are three Qt issues, you can use any AMD card can reproduce the issue.

      1. For the first issue:

      Test app uses Qt to create core profile 4.1 OpenGL context, it will call API glVertexAttribPointer but input parameter pointer is a pointer to system memory vertex data, which violates spec because
      OpenGL 4.1 context needs to bind a vertex buffer before calling glVertexAttribPointer, so AMD OGL driver will report the following error " glVertexAttribPointer in a Core context called without a bound
      Vertex Array Object [which is now required for Core Contexts]". Nvidia may not fully follow the OpenGL spec, so it can pass the test case.

      In Qt paint engine call sequence, before calling glVertexAttribPointer, it doesn’t bind an array buffer, it is not allowed after OpenGL spec 3.1 anymore

      glEnableVertexAttribArray(0)
      glGetUniformLocation(9, "fragmentColor") = 0
      glUniform4fv(0, 1, [0.941176, 0.941176, 0.941176, 1])
      glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0D5A8C2C)
      glDrawArrays(GL_TRIANGLE_FAN, 0, 4)
      

      The correct call sequence for OpenGL 3.1 above should be:

      glEnableVertexAttribArray(0);
      glBindBuffer(GL_ARRAY_BUFFER, VBO);
      glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
      glDrawArrays(GL_TRIANGLES, 0, 3);
      glDisableVertexAttribArray(0);
      

      App call stack:

       	Qt5Guid.dll!QOpenGLFunctions::glVertexAttribPointer(unsigned int indx, int size, unsigned int type, unsigned char normalized, int stride, const void * ptr) Line 2169	C++
       	Qt5Guid.dll!QOpenGL2PaintEngineExPrivate::setVertexAttributePointer(unsigned int arrayIndex, const float * pointer) Line 339	C++
       	Qt5Guid.dll!QOpenGL2PaintEngineExPrivate::composite(const QOpenGLRect & boundingRect) Line 1217	C++
       	Qt5Guid.dll!QOpenGL2PaintEngineExPrivate::fill(const QVectorPath & path) Line 770	C++
       	Qt5Guid.dll!QOpenGL2PaintEngineEx::fill(const QVectorPath & path, const QBrush & brush) Line 1260	C++
       	Qt5Guid.dll!QPaintEngineEx::fillRect(const QRectF & r, const QBrush & brush) Line 700	C++
       	Qt5Guid.dll!QPainter::fillRect(const QRect & r, const QBrush & brush) Line 6937	C++
       	Qt5Widgetsd.dll!fillRegion(QPainter * painter, const QRegion & rgn, const QBrush & brush) Line 2410	C++
       	Qt5Widgetsd.dll!QWidgetPrivate::paintBackground(QPainter * painter, const QRegion & rgn, int flags) Line 2444	C++
       	Qt5Widgetsd.dll!QWidgetPrivate::drawWidget(QPaintDevice * pdev, const QRegion & rgn, const QPoint & offset, int flags, QPainter * sharedPainter, QWidgetBackingStore * backingStore) Line 5582	C++
       	Qt5Widgetsd.dll!QWidgetPrivate::render(QPaintDevice * target, const QPoint & targetOffset, const QRegion & sourceRegion, QFlags<enum QWidget::RenderFlag> renderFlags) Line 5776	C++
       	Qt5Widgetsd.dll!QWidget::render(QPainter * painter, const QPoint & targetOffset, const QRegion & sourceRegion, QFlags<enum QWidget::RenderFlag> renderFlags) Line 5210	C++
       	Qt5Widgetsd.dll!QGraphicsProxyWidget::paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget) Line 1534	C++
       	Qt5Widgetsd.dll!_q_paintItem(QGraphicsItem * item, QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget, bool useWindowOpacity, bool painterStateProtection) Line 4312	C++
       	Qt5Widgetsd.dll!QGraphicsScenePrivate::drawItemHelper(QGraphicsItem * item, QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget, bool painterStateProtection) Line 4405	C++
       	Qt5Widgetsd.dll!QGraphicsScenePrivate::draw(QGraphicsItem * item, QPainter * painter, const QTransform * const viewTransform, const QTransform * const transformPtr, QRegion * exposedRegion, QWidget * widget, double opacity, const QTransform * const effectTransform, bool wasDirtyParentSceneTransform, bool drawItem) Line 4964	C++
       	Qt5Widgetsd.dll!QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem * item, QPainter * painter, const QTransform * const viewTransform, QRegion * exposedRegion, QWidget * widget, double parentOpacity, const QTransform * const effectTransform) Line 4855	C++
       	Qt5Widgetsd.dll!QGraphicsScene::drawItems(QPainter * painter, int numItems, QGraphicsItem * * items, const QStyleOptionGraphicsItem * options, QWidget * widget) Line 5388	C++
       	Qt5Widgetsd.dll!QGraphicsScene::render(QPainter * painter, const QRectF & target, const QRectF & source, Qt::AspectRatioMode aspectRatioMode) Line 1827	C++
       	HelloWorldOverlay.exe!COpenVROverlayController::OnSceneChanged(const QList<QRectF> & __formal) Line 186	C++
       	HelloWorldOverlay.exe!COpenVROverlayController::OnTimeoutPumpEvents() Line 243	C++
       	HelloWorldOverlay.exe!COpenVROverlayController::qt_static_metacall(QObject * _o, QMetaObject::Call _c, int _id, void * * _a) Line 79	C++
       	Qt5Cored.dll!QMetaObject::activate(QObject * sender, int signalOffset, int local_signal_index, void * * argv) Line 3740	C++
       	Qt5Cored.dll!QMetaObject::activate(QObject * sender, const QMetaObject * m, int local_signal_index, void * * argv) Line 3602	C++
       	Qt5Cored.dll!QTimer::timeout(QTimer::QPrivateSignal __formal) Line 198	C++
       	Qt5Cored.dll!QTimer::timerEvent(QTimerEvent * e) Line 256	C++
       	Qt5Cored.dll!QObject::event(QEvent * e) Line 1245	C++
       	Qt5Widgetsd.dll!QApplicationPrivate::notify_helper(QObject * receiver, QEvent * e) Line 3799	C++
       	Qt5Widgetsd.dll!QApplication::notify(QObject * receiver, QEvent * e) Line 3159	C++
       	Qt5Cored.dll!QCoreApplication::notifyInternal2(QObject * receiver, QEvent * event) Line 988	C++
       	Qt5Cored.dll!QCoreApplication::sendEvent(QObject * receiver, QEvent * event) Line 231	C++
       	Qt5Cored.dll!QEventDispatcherWin32Private::sendTimerEvent(int timerId) Line 657	C++
       	Qt5Cored.dll!qt_internal_proc(HWND__ * hwnd, unsigned int message, unsigned int wp, long lp) Line 449	C++
       	[External Code]	
       	[Frames below may be incorrect and/or missing, no symbols loaded for user32.dll]	
       	Qt5Cored.dll!QEventDispatcherWin32::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 845	C++
       	qwindowsd.dll!QWindowsGuiEventDispatcher::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 74	C++
       	Qt5Cored.dll!QEventLoop::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 135	C++
       	Qt5Cored.dll!QEventLoop::exec(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 210	C++
       	Qt5Cored.dll!QCoreApplication::exec() Line 1261	C++
       	Qt5Guid.dll!QGuiApplication::exec() Line 1640	C++
       	Qt5Widgetsd.dll!QApplication::exec() Line 2976	C++
       	HelloWorldOverlay.exe!main(int argc, char * * argv) Line 17	C++
       	HelloWorldOverlay.exe!WinMain(HINSTANCE__ * __formal, HINSTANCE__ * __formal, char * __formal, int __formal) Line 123	C++
      

      2. For the second the issue:

      After you fix the first issue, then you will see a corrupted test.bmp generated, the corruption is caused by:

      glTexSubImage2D(GL_TEXTURE_2D, 0, 107, 1, 1, 9, GL_RED, GL_UNSIGNED_BYTE, 143C25F8)
      
      static const char* const qopenglslMaskFragmentShader = "\n\
          varying   highp   vec2      textureCoords;\n\
          uniform           sampler2D maskTexture;\n\
          lowp vec4 applyMask(lowp vec4 src) \n\
          {\n\
              lowp vec4 mask = texture2D(maskTexture, textureCoords); \n\
              return src * mask.a; \n\
      }\n";
      

      According to Qt paint engine code, it uses GL_RED to upload a texture, so based on the OpenGL spec, the texture will be (GL_RED value, 0,0,1), but in pixel shader, it uses src * mask.a,
      which is a constant 0 value in AMD platform, and mask.a is wrong here, we should use mask.r to access a texture which only contains the red channel, so if we change the pixel shader to src * mask.r,
      then test app will generate a correct picture.

      3. For the third issue:

      After you fix the previous two issues, then you will still see spinbox corruption in test.bmp, and the corruptionis caused by:

      When creating the texture for Qt Spinbox, Qt paint engine doesn’t generate the mip map or even no call something like

      glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
      glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
      

      so the behavior is undefined, https://www.opengl.org/wiki/Common_Mistakes

      Attachments

        Issue Links

          No reviews matched the request. Check your Options in the drop-down menu of this sections header.

          Activity

            People

              lagocs Laszlo Agocs
              jeff-htc-vr Jeff liu
              Votes:
              0 Vote for this issue
              Watchers:
              11 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:

                Gerrit Reviews

                  There are no open Gerrit changes