Repository: pyqtgraph/pyqtgraph

Issue:
PyOpenGL rendering broken after upgrade from 0.11.1 to 0.12.1
### Short description
The Data lines (paths) are not correctly displayed using pyopengl after updating from 0.11.1 to 0.12.1.

### Code to reproduce
<!-- Please provide a minimal working example that reproduces the issue in the code block below.
     Ideally, this should be a full example someone else could run without additional setup. -->
```python
import numpy
import cProfile
import logging

import pyqtgraph as pg
from PyQt5 import QtCore,uic
from PyQt5.QtGui import *
from PyQt5.QtCore import QRect, QTimer

try:
    import OpenGL
    pg.setConfigOption('useOpenGL', True)
    pg.setConfigOption('enableExperimental', True)
except Exception as e:
    print(f"Enabling OpenGL failed with {e}. Will result in slow rendering. Try installing PyOpenGL.")

    

def program(columns=8, samples=10000, channels=64):
    app = QApplication([])
    win = pg.GraphicsLayoutWidget()
    pg.setConfigOptions(imageAxisOrder='row-major')
    win.resize(1280,768)
    win.ci.layout.setSpacing(0)
    win.ci.layout.setContentsMargins(0,0,0,0)
    win.show()

    data            = numpy.zeros((samples, channels+1))
    plots           = [win.addPlot(row=i/columns+1,col=i%columns) for i in range(channels)]
    curves          = list()

    x = numpy.linspace(0, 1, samples, endpoint=True)
    f = 2 # Frequency in Hz
    A = 1 # Amplitude in Unit
    y = A * numpy.sin(2*numpy.pi*f*x).reshape((samples,1)) # Signal

    data[:,0]   = x
    data[:,1:]  = numpy.repeat(y, channels, axis=1)
    
    for chn_no,p in enumerate(plots, 1):
        c       = pg.PlotCurveItem(pen=(chn_no,channels * 1.3))
        p.addItem(c)
        curves.append((c, chn_no))
          
    def update():
        nonlocal data

        data[:,1:] = numpy.roll(data[:,1:], 100, axis=0)
            
        for curve,data_index in curves:
            curve.setData(data[:,0],data[:,data_index])

    timer = QTimer()
    timer.timeout.connect(update)
    timer.start(30)
    return app.exec_()   


if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO)
    #cProfile.run("program()", sort="cumtime")
    program()
```

### Expected behavior
Before updating to 0.12.1 it looks like this:
![working](https://user-images.githubusercontent.com/35171947/117024472-50109e80-acfa-11eb-9be8-f4b430c78988.png)


### Real behavior

After updating:
![not_working](https://user-images.githubusercontent.com/35171947/117024571-674f8c00-acfa-11eb-9169-f3f2b7adaf7f.png)


### Tested environment(s)

 * PyQtGraph version: 0.12.1
 * Qt Python binding: 5.15.2
 * Python version: Python 3.9.2 (tags/v3.9.2:1a79785, Feb 19 2021, 13:44:55) [MSC v.1928 64 bit (AMD64)] on win32
 * NumPy version: <1.20.1
 * Operating system: Win10
 * Installation method: pip

complete pip list:

Package             Version
------------------- ------------
astroid             2.5.1
cffi                1.14.5
click               7.1.2
colorama            0.4.4
cycler              0.10.0
hidapi              0.10.1
isort               5.7.0
kiwisolver          1.3.1
lazy-object-proxy   1.5.2
matplotlib          3.4.0
mccabe              0.6.1
neo                 0.6.1
numpy               1.20.1
picosdk             1.0
Pillow              8.1.1
pilxi               3.19
pip                 20.2.3
pycparser           2.20
PyDAQmx             1.4.4
pylint              2.7.2
PyOpenGL            3.1.5
PyOpenGL-accelerate 3.1.5
PyOpenGL-Demo       3.0.0
pyparsing           2.4.7
PyQt5               5.15.2
pyqt5-plugins       5.15.2.2.0.1
PyQt5-sip           12.8.1
pyqt5-tools         5.15.2.3.0.2
pyqtgraph           0.11.1
PyqtTools           0.1
pyserial            3.5
python-dateutil     2.8.1
python-dotenv       0.15.0
PyVISA              1.11.3
PyVISA-py           0.5.2
qt5-applications    5.15.2.2.1
qt5-tools           5.15.2.1.0.1
quantities          0.12.4
scipy               1.6.1
setuptools          49.2.1
six                 1.15.0
sounddevice         0.4.1
toml                0.10.2
typing-extensions   3.7.4.3
wrapt               1.12.1
XlsxWriter          1.3.7


### Additional context



Discussion:
Hi @noxobscura thanks for creating this issue; we have known about it, but I keep forgetting to create the issue with a reproducible example.

A little context, in pyqtgraph 0.11.0 (and 0.11.1), pyqtgraph used the `QGLWidgets` which had deprecation notices in Qt5, but were the default OpenGL widgets for Qt4.  Qt5 rolled out `QOpenGLWidgets`, and Qt6 (which pyqtgraph now supports) does not have `QGLWidgets`, but only `QOpenGLWidgets`.   In other words, to support Qt6, pyqtgraph had to drop support for QGLWidgets and adopt QOpenGLWidgets in the process.  Unfortunately this also means we will not be bringing `QGLWidget` support back, so reverting to the old mechanism isn't realistic.

The issue you've posted here is unique to Windows, on macOS and Linux, the plots behave as intended.  We suspect an upstream bug of some kind is at play.

Many of the current active maintainers of pyqtgraph do not have extensive openGL experience, so while this issue is known, we don't know how to go about trying to fix it.  Because of that, I'm going to add the "help wanted" tag.

Wish I had better news, sorry!
That is a pitty. One can use the glViewport (ll 547) call within PlotCurveItem.py to get the curve at their place. However, panning/zoom etc is not working correctly then. And the worst part is, that it is super slow again. It seems that Qt changes settings under windows, which it is allowed to do if I understood it correctly.

I noticed that there is a GLViewWidget which seems to take care of a lot of things but is meant for 3D actually. I wonder if one could derivate a 2D version from this. Maybe someone now something about this GLViewWidget and how to use it?

EDIT: found a working example. Interestingly it runs way smoother with 0.11.1 than with 0.12.1 on my machine. There seems to be something awfully off with the new version with respect to the opengl stuff.
I realized that the example given above is from https://stackoverflow.com/questions/63855707/realtime-visualisation-bottleneck-with-pyqtgraph-plotcurveitem

A more minimal example demonstrating this issue can be found at https://github.com/pyqtgraph/pyqtgraph/pull/1525#issuecomment-770304898

Resolving patch:
diff --git a/pyqtgraph/graphicsItems/PlotCurveItem.py b/pyqtgraph/graphicsItems/PlotCurveItem.py
--- a/pyqtgraph/graphicsItems/PlotCurveItem.py
+++ b/pyqtgraph/graphicsItems/PlotCurveItem.py
@@ -568,6 +568,21 @@ def paintGL(self, p, opt, widget):
         p.beginNativePainting()
         import OpenGL.GL as gl
 
+        if sys.platform == 'win32':
+            # If Qt is built to dynamically load OpenGL, then the projection and
+            # modelview matrices are not setup.
+            # https://doc.qt.io/qt-6/windows-graphics.html
+            # https://code.woboq.org/qt6/qtbase/src/opengl/qopenglpaintengine.cpp.html
+            # Technically, we could enable it for all platforms, but for now, just
+            # enable it where it is required, i.e. Windows
+            tr = self.sceneTransform()
+            rect = widget.rect()
+            gl.glMatrixMode(gl.GL_PROJECTION)
+            gl.glLoadIdentity()
+            gl.glOrtho(rect.x(), rect.width(), rect.height(), rect.y(), -999999, 999999)
+            gl.glMatrixMode(gl.GL_MODELVIEW)
+            gl.glLoadTransposeMatrixf(QtGui.QMatrix4x4(tr).copyDataTo())
+
         ## set clipping viewport
         view = self.getViewBox()
         if view is not None:


Test patch: