# LazOpenGLContextEx Форк штатного пакета `LazOpenGLContext` (Lazarus `components/opengl`), в котором Qt5/Qt6-бэкенд построен на настоящем `QOpenGLWidget` вместо GLX. ## Зачем Штатный `TOpenGLControl` под `--ws=qt5/qt6` работает только в X11-сессии и вообще не собирается с Qt-виджетсетом на Windows/macOS: он руками создаёт GLX-контекст на `winId()`. Важно: `QLCLOpenGLWidget` из libQt6Pas — это **не** QOpenGLWidget, а голый QWidget с `WA_NativeWindow` и `paintEngine()=nullptr`, т.е. просто мишень для внешнего GLX-рендера (вызов на нём методов QOpenGLWidget = access violation — проверено). Здесь контекст создаёт сам Qt через платформенный API: | Платформа | Контекст | |------------------|----------| | Linux Wayland | EGL | | Linux X11 | GLX | | Windows (ws=qt6) | WGL | | macOS (ws=qt6) | CGL | Бэкенды gtk2/gtk3/win32/cocoa скопированы из штатного пакета без изменений (юниты переименованы с суффиксом `Ex`, чтобы не конфликтовать со стоковым пакетом). ## Состав - `openglcontextex.pas` — `TOpenGLControl` (класс называется так же, юнит `OpenGLContextEx`). - `glqtnativecontext.pas` — Qt-бэкенд поверх QOpenGLWidget. - `csrc/qlclglwidget.cpp` — **вспомогательная C++-библиотека** `libqlclglwidget.so`: наследник QOpenGLWidget с paintGL-хуком в Pascal + плоские экспорты (`makeCurrent`, `doneCurrent`, `isValid`, `setFormat`, `defaultFramebufferObject`, `devicePixelRatioF`). Грузится в рантайме: сначала рядом с исполняемым файлом, затем по системным путям. ## Сборка вспомогательной библиотеки (csrc/) | Где собираем | Команда | Результат | |---|---|---| | Linux | `make -C csrc` | `libqlclglwidget.so` | | macOS | `make -C csrc` (авто) или `make -C csrc macos` | `libqlclglwidget.dylib` | | Linux → Windows (кросс) | `make -C csrc windows` | `qlclglwidget.dll` (MinGW) | | Windows, MSYS2 MinGW64 shell | `make -C csrc` (авто) или `make -C csrc windows-native` | `qlclglwidget.dll` (MinGW) | | Windows, Qt MinGW-kit без pkg-config | `make -C csrc windows MINGW_CXX=g++ WIN_QT_INC=C:/Qt/6.x/mingw_64/include WIN_QT_LIB=C:/Qt/6.x/mingw_64/lib` | `qlclglwidget.dll` (MinGW) | | Windows, MSVC | `csrc\build-msvc.bat` из «x64 Native Tools Command Prompt» с выставленным `QTDIR` | `qlclglwidget.dll` (MSVC) | Плюс: ``` make -C csrc install # установить в /usr/local/lib (PREFIX/DESTDIR поддерживаются) make -C csrc install-app APPDIR=/путь/к/бинарнику # положить рядом с приложением ``` Для кросс-сборки нужен тулчейн mingw-w64 и **MinGW-сборка Qt6** (AUR `mingw-w64-qt6-base`, MXE, либо Qt MinGW-kit; пути переопределяются `MINGW_PREFIX`/`WIN_QT_INC`/`WIN_QT_LIB`). Для MSYS2: `pacman -S mingw-w64-x86_64-gcc mingw-w64-x86_64-qt6-base pkgconf make`. ⚠ **ABI:** MinGW-DLL работает только с MinGW-сборкой Qt6 на целевой машине, MSVC-DLL — только с MSVC-Qt (официальные бинарники Qt из online-инсталлятора — MSVC). Выбирайте вариант под ту Qt6, с которой собрана libQt6Pas приложения. ## Использование В проекте: зависимость `LazOpenGLContext` → `LazOpenGLContextEx`, в uses: `OpenGLContext` → `OpenGLContextEx`. ``` make -C csrc lazbuild --ws=qt6 lazopenglcontextex.lpk make -C csrc install-app APPDIR=<каталог с бинарником приложения> ``` ## Как устроен Qt-бэкенд - Qt сам делает контекст текущим и биндит FBO виджета перед вызовом `paintGL()`; оттуда доставляется `LM_PAINT`, так что весь рендер в `OnPaint` работает как раньше. - `SwapBuffers` внутри paint — no-op (композитингом FBO занимается Qt после возврата из `paintGL`); вне paint — планирует перерисовку (`QWidget::update`). - `MakeCurrent`/`ReleaseContext` вне paint → `QOpenGLWidget::makeCurrent/doneCurrent`. До первого показа виджета контекста ещё нет — `MakeCurrent` вернёт False. - `LOpenGLViewport` (AutoResizeViewport) умножает координаты на devicePixelRatio. ## Ограничения / нюансы - **Не вызывать `glBindFramebuffer(..., 0)`** — QOpenGLWidget рендерит в свой FBO. - **Альфа фреймбуфера = прозрачность виджета.** Qt композитит FBO с учётом альфы; легаси-GL-код после блендинга оставляет alpha<1, и виджет просвечивал бы насквозь. Поэтому обёртка после каждого paintGL принудительно заливает альфу единицей (`QLCLGLWidget_setForceOpaque`, включено по умолчанию). Отключается автоматически, если контрол запросил `AlphaBits > 0` — тогда альфа остаётся под контролем приложения. - **SharedControl игнорируется**: Qt автоматически шарит контексты всех QOpenGLWidget внутри одного top-level окна. Для шаринга между окнами нужно выставить `Qt::AA_ShareOpenGLContexts` до создания QApplication. - **Windows + qt6**: чтобы Qt не выбрал ANGLE/GLES (где нет immediate mode), выставить `QT_OPENGL=desktop` или атрибут `AA_UseDesktopOpenGL`. - **HiDPI (devicePixelRatio > 1)**: FBO больше логического размера виджета. Явные вызовы `glViewport` в коде приложения должны умножать на dpr сами. - AUXBuffers не поддерживаются QSurfaceFormat (игнорируются). - Qt4 (LCLQT), gtk1 и carbon из форка выброшены. ## Статус проверки - Linux Wayland (KDE, qt6): спектр EWSDR рендерится через GL, стартует без ошибок, скриншот подтверждён (2026-07-03). - Linux XWayland/xcb: стартует без ошибок. - Windows/macOS: не проверялось (build.sh под них ещё нет — нужен аналог с MSVC/clang и Qt-заголовками).