Mam widget który używam do wizualizacji danych dla użytkownika w GUI
chciałbym użyć tego samego widget-u "offscreen" aby wygenerować plik wideo w tle (poza wątkiem GUI)

Czy to jest możliwe ?
Dla jednego wątku działa ale na konsoli pojawiają się ostrzeżenia
"Attempting to create QWindow-based QOffscreenSurface outside the gui thread. Expect failures."

Jak jest jeden watek to "Expect failures." nie pojawiły się
Jak zwiększam ilość wątków to prawdopodobieństwo failures wzrasta

Jak to zrobić poprawnie ?
I przykładowy kod

supportsThreadedOpenGL zwraca TRUE

UWAGA ! Ten kod jest niebezpieczny dla Linux-a
wartość THREAD_COUNT = 8 zawiesza system operacyjny tak skutecznie
że działa tylko reset

#include <thread>

#include <QApplication>
#include <QPushButton>
#include <QOffscreenSurface>
#include <QPainter>
#include <QWidget>
#include <QOpenGLWidget>
#include <QOpenGLShaderProgram>
#include <QOpenGLFunctions>


//! [3]
static const char *vertexShaderSource =
    "attribute highp vec4 posAttr;\n"
    "attribute lowp vec4 colAttr;\n"
    "varying lowp vec4 col;\n"
    "uniform highp mat4 matrix;\n"
    "void main() {\n"
    "   col = colAttr;\n"
    "   gl_Position = matrix * posAttr;\n"
    "}\n";

static const char *fragmentShaderSource =
    "varying lowp vec4 col;\n"
    "void main() {\n"
    "   gl_FragColor = col;\n"
    "}\n";
//! [3]


class WidgetSample : public QOpenGLWidget, protected QOpenGLFunctions
{
public:
    WidgetSample(QWidget *parent = nullptr): QOpenGLWidget(parent){};
    ~WidgetSample(){};
    QOpenGLShaderProgram *m_program = nullptr;
    int m_frame = 0;
    GLint m_posAttr = 0;
    GLint m_colAttr = 0;
    GLint m_matrixUniform = 0;
protected:
    void initializeGL() override
    {
        initializeOpenGLFunctions();
        glClearColor(1, 0, 0, 0.5);

        m_program = new QOpenGLShaderProgram(this);
        m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource);
        m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource);
        m_program->link();
        m_posAttr = m_program->attributeLocation("posAttr");
        Q_ASSERT(m_posAttr != -1);
        m_colAttr = m_program->attributeLocation("colAttr");
        Q_ASSERT(m_colAttr != -1);
        m_matrixUniform = m_program->uniformLocation("matrix");
        Q_ASSERT(m_matrixUniform != -1);        
    };
    
    void paintGL() override
    {
        QPainter painter;
        painter.begin(this);
        painter.beginNativePainting();

        const qreal retinaScale = devicePixelRatio();
        glViewport(0, 0, width() * retinaScale, height() * retinaScale);

        glClear(GL_COLOR_BUFFER_BIT);

        m_program->bind();

        QMatrix4x4 matrix;
        matrix.perspective(60.0f, 4.0f / 3.0f, 0.1f, 100.0f);
        matrix.translate(0, 0, -2);
        matrix.rotate(100.0f * m_frame / /* screen()->refreshRate()*/ 60.0, 0, 1, 0);

        m_program->setUniformValue(m_matrixUniform, matrix);

        static const GLfloat vertices[] = {
            0.0f,  0.707f,
            -0.5f, -0.5f,
            0.5f, -0.5f
        };

        static const GLfloat colors[] = {
            1.0f, 0.0f, 0.0f,
            0.0f, 1.0f, 0.0f,
            0.0f, 0.0f, 1.0f
        };

        glVertexAttribPointer(m_posAttr, 2, GL_FLOAT, GL_FALSE, 0, vertices);
        glVertexAttribPointer(m_colAttr, 3, GL_FLOAT, GL_FALSE, 0, colors);

        glEnableVertexAttribArray(m_posAttr);
        glEnableVertexAttribArray(m_colAttr);

        glDrawArrays(GL_TRIANGLES, 0, 3);

        glDisableVertexAttribArray(m_colAttr);
        glDisableVertexAttribArray(m_posAttr);

        m_program->release();

        ++m_frame;
        painter.endNativePainting();

        painter.setClipRect(rect());

        painter.fillRect(QRect(32,32,300,64),Qt::blue);

        QFont font;
        font.setPointSize(32);
        painter.setFont(font);
        painter.setPen (QColor(11, 99, 99, 255));

        painter.drawText(rect(),Qt::AlignVCenter | Qt::AlignHCenter, "Hello world"   );

        painter.end();
    }
};



#define THREAD_COUNT 1 

auto startThread= [](int threadNum){
    std::thread *koza = new std::thread([threadNum](){
        WidgetSample * w = new WidgetSample;
        w->resize(800,480);

        // QSurfaceFormat glFormat;
        // glFormat.setVersion(3, 3);
        // glFormat.setProfile(QSurfaceFormat::CoreProfile);
        // glFormat.setRenderableType(QSurfaceFormat::OpenGL);

        // QOffscreenSurface *surface = new QOffscreenSurface();
        // surface->setFormat(glFormat);
        // surface->create(); 
        // w->context()->makeCurrent(surface);

        for(int i=0; i<16;++i)
        {
            w->update();
            QString fnameOut = QString("mageWG2_%1_%2.png").arg(i).arg(threadNum);
            qDebug()<<"fnameOut:" << fnameOut <<" "<<threadNum;
            w->grabFramebuffer().save(fnameOut);
        };
    });

    return koza; 
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    WidgetSample mainForm;

    qDebug() <<"mainForm.context()->supportsThreadedOpenGL()=="<<  mainForm.context()->supportsThreadedOpenGL();

    QPushButton *pushButton = new QPushButton(&mainForm);
    pushButton->setText("start threads");
    pushButton->resize(88,44);
    QObject::connect(pushButton, &QPushButton::clicked, &mainForm, [&](){
        for(int i=0; i<THREAD_COUNT ; ++i)
        {
            auto t= startThread(i);
        }
    });

    mainForm.setGeometry(100,100,300,200);
    mainForm.show();
    return a.exec();
}
///// CMAKE ////////////////// 
// cmake_minimum_required(VERSION 3.5)
// project(WidgetSample VERSION 0.1 LANGUAGES CXX)
// set(CMAKE_AUTOUIC ON)
// set(CMAKE_AUTOMOC ON)
// set(CMAKE_AUTORCC ON)
// set(CMAKE_CXX_STANDARD 17)
// set(CMAKE_CXX_STANDARD_REQUIRED ON)
// find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets  OpenGL) 
// find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets  OpenGL) 
// add_executable(WidgetSample main.cpp)
// target_link_libraries(WidgetSample PRIVATE Qt${QT_VERSION_MAJOR}::Widgets  Qt${QT_VERSION_MAJOR}::OpenGL ) # Qt::OpenGLWidgets