QUItCoding / qnanopainter

Library for implementing OpenGL accelerated Qt (Quick) C++ UI components.
http://quitcoding.com
Other
405 stars 79 forks source link

patch to compile on Raspberry Pi/Raspbian Stretch and extremely variable performance with qnanopainter_vs_qpainter_demo testing #45

Closed NielsMayer closed 4 years ago

NielsMayer commented 5 years ago

Using https://www.tal.org/tutorials/building-qt-512-raspberry-pi I built latest Qt release on latest Raspbian Stretch distro (aka debian 9)

Unfortunately, when compiling qnanopainter it gives compilation errors:

g++ -c -pipe -march=armv8-a -mtune=cortex-a53 -mfpu=crypto-neon-fp-armv8 -O2 -std=gnu++11 -Wall -W -D_REENTRANT -fPIC -DQNANO_QT_GL_INCLUDE -DQNANO_ENABLE_GLES3 -DQT_NO_DEBUG_OUTPUT -DQT_NO_INFO_OUTPUT -DQT_NO_DEBUG -DQT_QUICK_LIB -DQT_GUI_LIB -DQT_QML_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -I. -I../../libqnanopainter -I/opt/Qt5.12/include -I/opt/Qt5.12/include/QtQuick -I/opt/Qt5.12/include/QtGui -I/opt/Qt5.12/include/QtQml -I/opt/Qt5.12/include/QtNetwork -I/opt/Qt5.12/include/QtCore -I. -I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads -I/opt/vc/include/interface/vmcs_host/linux -I/opt/Qt5.12/mkspecs/linux-rpi3-g++ -o qnanobackendgl2.o ../../libqnanopainter/private/qnanobackendgl2.cpp In file included from ../../libqnanopainter/private/qnanobackendgl2.cpp:12:0: ../../libqnanopainter/nanovg/nanovg_gl_wrapped.h: In function ‘int glnvg__renderCreateTexture(void*, int, int, int, int, const unsigned char*)’: ../../libqnanopainter/nanovg/nanovg_gl_wrapped.h:742:33: error: ‘GL_UNPACK_ROW_LENGTH’ was not declared in this scope QNANO_GLFWRAPPER glPixelStorei(GL_UNPACK_ROW_LENGTH, tex->width); ^~~~~~~~~~~~~~~~~~~~ ../../libqnanopainter/nanovg/nanovg_gl_wrapped.h:743:33: error: ‘GL_UNPACK_SKIP_PIXELS’ was not declared in this scope QNANO_GLFWRAPPER glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); ^~~~~~~~~~~~~~~~~~~~~ ../../libqnanopainter/nanovg/nanovg_gl_wrapped.h:744:33: error: ‘GL_UNPACK_SKIP_ROWS’ was not declared in this scope QNANO_GLFWRAPPER glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); ^~~~~~~~~~~~~~~~~~~ ../../libqnanopainter/nanovg/nanovg_gl_wrapped.h:750:51: error: ‘GL_GENERATE_MIPMAP’ was not declared in this scope QNANO_GLFWRAPPER glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); ^~~~~~~~~~~~~~~~~~ ../../libqnanopainter/nanovg/nanovg_gl_wrapped.h: In function ‘int glnvg__renderUpdateTexture(void*, int, int, int, int, int, const unsigned char*)’: ../../libqnanopainter/nanovg/nanovg_gl_wrapped.h:833:33: error: ‘GL_UNPACK_ROW_LENGTH’ was not declared in this scope QNANO_GLFWRAPPER glPixelStorei(GL_UNPACK_ROW_LENGTH, tex->width); ^~~~~~~~~~~~~~~~~~~~ ../../libqnanopainter/nanovg/nanovg_gl_wrapped.h:834:33: error: ‘GL_UNPACK_SKIP_PIXELS’ was not declared in this scope QNANO_GLFWRAPPER glPixelStorei(GL_UNPACK_SKIP_PIXELS, x); ^~~~~~~~~~~~~~~~~~~~~ ../../libqnanopainter/nanovg/nanovg_gl_wrapped.h:835:33: error: ‘GL_UNPACK_SKIP_ROWS’ was not declared in this scope QNANO_GLFWRAPPER glPixelStorei(GL_UNPACK_SKIP_ROWS, y); ^~~~~~~~~~~~~~~~~~~ Makefile:3703: recipe for target 'qnanobackendgl2.o' failed make[1]: *** [qnanobackendgl2.o] Error 1 Some of the undeclared values are present in include files so it is unclear what is missing to get these defined. I will investigate further but wanted to report this problem in case others are seeing it.

npm@rpi2:/usr/local/src/qnanopainter$ grep -r GL_UNPACK_ROW_LENGTH /usr/include/
/usr/include/epoxy/gl_generated.h:#define GL_UNPACK_ROW_LENGTH                                            0x0CF2
/usr/include/epoxy/gl_generated.h:#define GL_UNPACK_ROW_LENGTH_EXT                                        0x0CF2
/usr/include/GL/gl.h:#define GL_UNPACK_ROW_LENGTH                       0x0CF2
/usr/include/GL/glcorearb.h:#define GL_UNPACK_ROW_LENGTH              0x0CF2

npm@rpi2:/usr/local/src/qnanopainter$ grep -r GL_UNPACK_ROW_LENGTH /opt/Qt5.12/include/
/opt/Qt5.12/include/QtGui/5.12.3/QtGui/private/qopengltexturehelper_p.h:        functions->glGetIntegerv(GL_UNPACK_ROW_LENGTH, &val);
/opt/Qt5.12/include/QtGui/5.12.3/QtGui/private/qopengltexturehelper_p.h:        functions->glPixelStorei(GL_UNPACK_ROW_LENGTH, options.rowLength());
/opt/Qt5.12/include/QtGui/qopengles2ext.h:#define GL_UNPACK_ROW_LENGTH_EXT          0x0CF2

qnanopainter.raspi-fail.txt

NielsMayer commented 5 years ago

Actually the search I should've done is this, as the raspberry pi has these included non-opensource headers from Broadcom for the raspberry pi GPU.

npm@rpi2:~$ grep -r GL_UNPACK_ROW_LENGTH /opt/vc/include
/opt/vc/include/GLES2/gl2ext.h:#define GL_UNPACK_ROW_LENGTH                                    0x0CF2

Turns out one of the other problems is that the include.pri test for "linux-rasp-*" doesn't actually trigger on a raspbian compile...

Bottom line is I eventually got qnanopainter to successfully compile AND run on the Raspberry Pi with some minor changes to force a GLES2 build. Qnanopainter now runs full screen on the Raspberry Pi console using EGLFS.

Enclosed is a patch to fix this . I will do a quick lookover and test/verification and then submit a pull request containing this fix.

qnanopainter.patch.txt

Sadly performance is lacking (on 1080P display). For default qnanopainter_vs_qpainter_demo setup

These numbers are for GPU/memory split with GPU having 128M. No change in performance noted for 256M and 320M allocated to GPU on Raspberry Pi 3 with 1G total memory.

In contrast, FYI, your Cinematic experience app (my version at https://github.com/NielsMayer/android/tree/master/Qt5_CinematicExperience_1.0 ) runs smoothly on the raspberry pi with 128M GPU allocation. Certainly displaying better FPS rates than the above.

QUItCoding commented 5 years ago

Good stuff, thanks!

Raspberry Pi should be detected by include.pri to use GLES but obviously it fails for you... I don't think special case like in you preliminary patch should be needed though, doesn't it choose build_gles_backends with "linux-rasp-*"? Other issue can then be that need to force not use GLES3 (disable QNANO_ENABLE_GLES3). Or alternatively modify qnanobackend.h so that without QNANO_QT_GL_INCLUDE it will include GLES2/gl2ext.h correctly... Don't know, waiting how simple patch you will end up :)

Lacking performance is also interesting. VideoCore IV GPU in Raspberry Pi is notably weak with fragment shaders, but wouldn't expect it to be that weak... Anyway please continue experimenting!

NielsMayer commented 5 years ago

The current way include.pri works attempted to compile qnanobackendgles3.cpp and fails due to lack of GL3 support. A current bug in include.pri is that " linux-rasp-*" isn't triggered on the raspberry pi (at least for Qt5.12.3) and both build_gles_backends and build_gl_backends are built; the latter causing compile errors. As I wasn't able to find a raspberry-pi specific predicate, I ended up using exists("/opt/vc/include/GLES2/gl2.h") { ... } which checks for the unique location of the Broadcom GL headers on the raspberry pi. If you know of a more elegant solution, please let me know!

There is a possible future solution for the raspberry pi which sidesteps the proprietary broadcomm GL headers under /opt/vc/include/{EGL/, GLES/,GLES2/} per https://www.raspberrypi.org/forums/viewtopic.php?t=159853 using /boot/config.txt setting dtoverlay=vc4-fkms-v3d . However setting it seems to break all existing working code, e.g. eglfs-based apps, Kodi, etc. TBD if the Raspberry Pi can be configured this way for Qt5.12 and built using more standard GL implementation. Seems like better performance would be available through more standard X server and GLX based mechanisms but the open-source vc4-fkms-v3d drivers don't seem to be a standard part of raspbian yet. It is not clear when that would happen and become mainstream and supported https://anholt.github.io/twivc4/2018/10/30/twiv/

Note lots of problems w/ eglfs on pi: https://www.raspberrypi.org/forums/viewtopic.php?t=156270 (eglfs is 10x slower than EGL in X.org) https://www.qlcplus.org/forum/viewtopic.php?t=12122 (Raspbian Stretch + VC4 + Qt5 = total mess)

So it may not make a lot of sense to start optimizing qnanopainter for the raspi eglfs backend and wait for a more definitive open source solution. Unfortunately the last link above makes that look unlikely or easy.

NielsMayer commented 5 years ago

My hunch is that internally eglfs is actually doing non-accelerated software rendering, which is why we're seeing speeds equivalent to what qnanopainter would be doing under software rendering. QPainter runs faster in this case as it requires less software to run in CPU to emulate the GPU.

In the "eglfs is 10x slower than EGL in X.org" link above i note the comment: "In the latter case the widgets' contents are rendered using the CPU into images, which are then uploaded into textures and composited by the plugin." That would explain why eglfs is slower. "

There is also the oddity that antialiasing isn't working in QML Shape Extension -- perhaps because it too is actually being software emulated?

NielsMayer commented 5 years ago

So I have a much cleaner patch available, that I want to try a few more things on before giving up on attempting additional support of qnanobackendgl2 on top of the qnanobackendgles2 that works currently.

Prior i had a hunch that acceleration was not happening, but it proveably is --- but not for all the tests available in qnanopainter_vs_qpainter_demo.

Also, under GLES2, the QML Shape extension test backend is showing as "GeometryRenderer" -- in comparison launching as QT_QPA_PLATFORM=xcb qnanopainter_vs_qpainter_demo under X windows indicates clearly the Software backend is used.

Additionally, I noticed the CPU was running at 600Mhz during the previous testing. Because the 'ondemand' governor is used by default. To make sure it is running at 1200Mhz (I just have regular Pi3B) you have to do (and install cpufrequtils) cpufreq-set -g performance -c 0.

Using the 'performance' governor, the enclosed spreadsheet gives the performance numbers vs a number of tests.

qnanopainter.performance.xlsx qnanopainter.performance.pdf

PS: Using "Flower" test and No AntiAliasing results in 60fps under XML Shape extension. Note that QML shape extension doesn't actually display any of the tests as antialiased, but performs better with antialiasing off, with no visible difference. On the flower test, with QML Shape extension, if you leave it running for a minute or two, the display glitches out with error output a stream of QOpenGLFramebufferObject: Framebuffer incomplete attachment. Likewise the bezier tests show significant visual glitches, artefacts and flashing running standalone under QML Shape extension. The QPainter and QNanoPainter versions display correctly.

NielsMayer commented 5 years ago

FYI, when running with EGLFS debug output, a number of sizes show up as "-1", and worrying stuff about alpha size 0, 0 samples, 0 sample buffers....

npm@rpi2:/usr/local/src/qnanopainter$ QT_QPA_EGLFS_DEBUG=1 examples/qnanopainter_vs_qpainter_demo/qnanopainter_vs_qpainter_demo 
Unable to query physical screen size, defaulting to 100 dpi.
To override, set QT_QPA_EGLFS_PHYSICAL_WIDTH and QT_QPA_EGLFS_PHYSICAL_HEIGHT (in millimeters).
libpng warning: iCCP: known incorrect sRGB profile
Created context for format QSurfaceFormat(version 2.0, options QFlags<QSurfaceFormat::FormatOption>(), depthBufferSize 24, redBufferSize -1, greenBufferSize -1, blueBufferSize -1, alphaBufferSize -1, stencilBufferSize 8, samples -1, swapBehavior QSurfaceFormat::DoubleBuffer, swapInterval 1, colorSpace QSurfaceFormat::DefaultColorSpace, profile  QSurfaceFormat::NoProfile) with config:
        EGL_BUFFER_SIZE: 16
        EGL_ALPHA_SIZE: 0
        EGL_BLUE_SIZE: 5
        EGL_GREEN_SIZE: 6
        EGL_RED_SIZE: 5
        EGL_DEPTH_SIZE: 24
        EGL_STENCIL_SIZE: 8
        EGL_CONFIG_CAVEAT: 12344
        EGL_CONFIG_ID: 17
        EGL_LEVEL: 0
        EGL_MAX_PBUFFER_HEIGHT: 2048
        EGL_MAX_PBUFFER_PIXELS: 4194304
        EGL_MAX_PBUFFER_WIDTH: 2048
        EGL_NATIVE_RENDERABLE: 1
        EGL_NATIVE_VISUAL_ID: 107544
        EGL_NATIVE_VISUAL_TYPE: 12344
        EGL_SAMPLES: 0
        EGL_SAMPLE_BUFFERS: 0
        EGL_SURFACE_TYPE: 1639
        EGL_TRANSPARENT_TYPE: 12344
        EGL_TRANSPARENT_BLUE_VALUE: 0
        EGL_TRANSPARENT_GREEN_VALUE: 0
        EGL_TRANSPARENT_RED_VALUE: 0
        EGL_BIND_TO_TEXTURE_RGB: 1
        EGL_BIND_TO_TEXTURE_RGBA: 1
        EGL_MIN_SWAP_INTERVAL: 0
        EGL_MAX_SWAP_INTERVAL: 2147483647
NielsMayer commented 4 years ago

I closed/archived the associated PR and I'm no longer tracking this issue as I'm no longer seeking to use Raspberry Pi with Qt as it has an underpowered and obsolete GPU.