Strange bug with newer drivers and Qt5

Our company has developed a game client based on Qt5. Since a few weeks we got reports of our players that after a certain amount of time the game stutters for a few seconds and then continues without that effect happening again.
We could narrow it down to a minimal example. It seems to occur only on newer NVIDIA drivers (we tried 416 and 418, under 3xx.xx the bug didn’t happen).
We contacted the Qt company and the could reproduce it but they think its a bug in the NVIDIA driver since it didn’t happen in older versions of the driver. So I hope somebody here can clarify what exactly happens.

  • You need to have the Qt5 framework installed (we tried 5.5.1, 5.11 and the newest 5.12.1 versions which are all affected). The open source version is enough to try this. We have tried the msvc2017 32-bit version and the mingw 64-bit version.
  • In the bin-directory there exists a executable named "qmlscene.exe" which can be used to execute a so called QML-file which is some kind of declarative UI language with javascript
  • Before you start it you should set two environment variables wich set the size of the used texture atlas. The bigger the atlas the longer the stutter. You should set at least 4096x4096 pixels ``` set QSG_ATLAS_WIDTH=4096 set QSG_ATLAS_HEIGHT=4096 ```
  • Save the example below as test.qml and run it with qmlscene.exe ``` qmlscene.exe test.qml ```
  • After running smooth for a few seconds you will see the animation stuttering heavily for a short while. Then it's running normally again. The stutter seems to appear somewhere within the NVIDIA OpenGL driver (nvoglv32.dll). At least thats what the profiler stack trace shows which can't be narrowed down because of missing debug symbols.

Here is the QML-file to run:

import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.2
import QtQuick.Dialogs 1.0

Window {
  id: launcherWindow
  color: "grey"
  width: 800
  height: 600

  property int drawnFrames: 0

  // this is important since it triggers the bug
  // when an image element is loaded directly at the beginning that has the property
  // smooth set to "false" the effect happens. If smooth is set to "true" the bug won't appear
  Image {
    source: "background.png"
    smooth: false
  }

  Text {
    text: "Drawn Frames: " + drawnFrames
    color: "white"
    font.pixelSize: 20
  }

  Rectangle {
    width: 400
    height: 200
    anchors.horizontalCenter: parent.horizontalCenter
    anchors.verticalCenter: parent.verticalCenter
    Canvas {
      id: canvas
      property real progress: 0.0
      anchors.fill: parent

      Timer {
        id: animationTimer
        property int direction: 1
        interval: 25
        repeat: true
        running: true
        onTriggered: {
          canvas.progress += 0.002 * direction;
          if (canvas.progress > 1.0 || canvas.progress < 0.0) {
            direction = -1 * direction;
          }
          // this is the other important part. You need a canvas element which is periodically redrawn via
          // "requestPaint". The bigger the canvas element (which should mean more pixels redrawn) the sooner
          // the bug occurs
          canvas.requestPaint();
        }
      }

      onPaint: {
          var ctx = getContext("2d");
          ctx.reset();
          ctx.fillStyle = "blue";
          ctx.fillRect(0, 0, progress * width, height);
          drawnFrames += 1;
      }
    }
  }
}

A bit of technical background:
Qt5 uses a scenegraph to render scenes described in QML files. The base technology is called QtQuick. It has an OpenGL backend which will be driven by the Qt5 framework. The developer only declares simple UI elements like in the example above. All the resulting OpenGL calls will be done directly by the QtQuick backend.
For images an automatically managed texture atlas is used. Qt uploads images into this singleton texture atlas to have less context switches between draw calls.
The effect only occurs when an image element exists that has “smooth” set to “false” which actually means draw it without filtering. This image element must be loaded at application start (so I guess it has something to do with initializing the graphics system and the texture atlas). Image elements that are loaded dynamically at a later time won’t trigger the effect.
Also the size of the texture atlas has a direct impact on the length of the stutter. It seems like the texture is maybe reinitialized.
The bug itself is triggered by using a Canvas-element (like the javascript canvas element in browsers) which has to be redrawn periodically. There seems to be a direct relation with the number of redrawn pixels. If I double the size of the canvas element the effect will happen after half the drawn frames.

I can’t say if the bug occurs because the Qt5 framework does something strange in OpenGL or that it’s really a driver bug which is new in 41x versions.

Hello,

I have forwarded this on to our engineers, and a bug was filed for the issue. I will do my best to update you here in the thread when new information becomes available.

Best regards,
Tom

scheungrab, Could you share OS version and GPU used? Thanks!

The operating system is Windows 10 Version 1709
Here is the log from the NVIDIA control panel

[Anzeige]
Betriebssystem:	Windows 10 Pro, 64-bit
DirectX-Version:	12.0 
GPU-Prozessor:		GeForce GTX 1050
Treiberversion:		418.91
Treibertyp:		Standard
Direct3D-API-Version:	12
Direct3D-Funktionsebene:	12_1
CUDA-Kerne:		640 
Kerntakt:		1354 MHz 
Speicher-Datenrate:	7.01 Gbps
Speicherschnittstelle:	128-Bit 
Speicherbandbreite:	112.13 GB/s
Gesamter verfügbarer Grafikspeicher:	10176 MB
Dedizierter Videospeicher:	2048 MB GDDR5
System-Videospeicher:	0 MB
Freigegebener Systemspeicher:	8128 MB
Video-BIOS-Version:	86.07.39.40.9B
IRQ:			Not used
Bus:			PCI Express x16 Gen3
Geräte-ID:		10DE 1C81 37661458
Teilenummer:		G210 0001

[Komponenten]

nvui.dll		8.17.14.1891		NVIDIA User Experience Driver Component
nvxdplcy.dll		8.17.14.1891		NVIDIA User Experience Driver Component
nvxdbat.dll		8.17.14.1891		NVIDIA User Experience Driver Component
nvxdapix.dll		8.17.14.1891		NVIDIA User Experience Driver Component
NVCPL.DLL		8.17.14.1891		NVIDIA User Experience Driver Component
nvCplUIR.dll		8.1.940.0		NVIDIA Control Panel
nvCplUI.exe		8.1.940.0		NVIDIA Control Panel
nvWSSR.dll		25.21.14.1891		NVIDIA Workstation Server
nvWSS.dll		25.21.14.1891		NVIDIA Workstation Server
nvViTvSR.dll		25.21.14.1891		NVIDIA Video Server
nvViTvS.dll		25.21.14.1891		NVIDIA Video Server
nvLicensingS.dll		6.14.14.1891		NVIDIA Licensing Server
nvDevToolS.dll		25.21.14.1891		NVIDIA 3D Settings Server
nvDispSR.dll		25.21.14.1891		NVIDIA Display Server
NVMCTRAY.DLL		25.21.14.1891		NVIDIA Media Center Library
nvDispS.dll		25.21.14.1891		NVIDIA Display Server
PhysX		09.18.0907		NVIDIA PhysX
NVCUDA.DLL		25.21.14.1891		NVIDIA CUDA 10.1.95 driver
nvGameSR.dll		25.21.14.1891		NVIDIA 3D Settings Server
nvGameS.dll		25.21.14.1891		NVIDIA 3D Settings Server

I also have a apitrace file that reproduces the problem. I tried it on the machine of a colleague. He has an older driver and didn’t show the stutter with the same trace replayed. But on my machine the stutter is visible when replaying the apitrace.
If you wan’t I can also send you the file (which is about 150kb packed). Also I can send you a trace of the same scene that doen’t have the error (when you don’t set “smooth” in the Image element to “false”) so you can look for the differences.

AScheungrab, Thanks for the quick response. We have reproduced the issue. Engineering team will look into this issue.