Mastodon

Ciao a tutti!

Nell’ultima settimana ho ottenuto progressi con la libreria di rendering QML (guarda il codice qui)

Si sta comportando come dovrebbe – calcola un file QML in ingresso per esportare fotogrammi in un specifico formato facendo un rendering il più rapidamente possibile (con QQuickRenderControl). Se vuoi testarlo – c’è un accesso a CLI attraverso un eseguibile (che è una delle cose sulle quali ho lavorato la scorsa settimana) per la libreria nella cartella per i test qui (assicurati di leggere il file README prima di procedere!)

Proviamo adesso a capire cosa succede realmente nel nucleo della libreria, cioè nella parte dedicata al rendering.

Per fare un rendering in QML, l’approccio più ovvio è quello di catturare una “schermata” per ogni fotogramma usando un metodo grab () che cattura tutti i pixel in ogni istante, e fare il rendering – questo sistema non è solo dannatamente lento e costoso, ma anche impedisce l’esecuzione del calcolo a un frame rate personalizzato.

Ed è a questo punto che entra in gioco QQuickRenderControl. QQuickRenderControl è usato per il rendering del contenuto Qt Quick (leggi QML) in qualcosa d’altro in modo molto controllabile. Se leggi la documentazione ufficiale, quel ‘qualcosa’ è un ‘offscreen render target’ (obiettivo di rendering fuori schermo) – l’enfasi su ‘offscreen’ – che significa che noi possiamo dire a una nostra ‘dummy window’ o surface (finestra o superficie finta) di calcolare il nostro QML in qualcosa d’altro (un QOpenGLFramebufferObject per essere specifici) e anche in modo piuttosto veloce!

Questa era la spiegazione a parole, ora vediamo un po’ di codice – non voglio confonderti (ulteriormente) ma questo è essenziale perché nel nucleo di questa libreria si trova il motore di rendering.

Prima di cominciare a lanciare dei calcoli è necessario fare il setup di QQuickRenderControl :

1) Determinare il formato della superficie sulla quale andremo ad eseguire il rendering.

QSurfaceFormat format;
format.setDepthBufferSize(16);
format.setStencilBufferSize(8);

2) Determinare l’OpenGL context

m_context = std::make_unique<QOpenGLContext>();
m_context->setFormat(format);
m_context->create();

3) Determinare la superficie finta (dummy surface)

m_offscreenSurface = std::make_unique<QOffscreenSurface>();
m_offscreenSurface->setFormat(m_context->format());
m_offscreenSurface->create();

4) Determinare il RenderControl e la finta finestra come obiettivo (target dummy window)

m_renderControl = std::make_unique<QQuickRenderControl>(this);
m_quickWindow = std::make_unique<QQuickWindow>(m_renderControl.get());
m_context->makeCurrent(m_offscreenSurface.get());
m_renderControl->initialize(m_context.get());

5) Crea un oggetto per il  frame buffer, e dire a QuickWindow di calcolare l’oggetto

m_fbo = std::make_unique<QOpenGLFramebufferObject>(m_size * m_dpr, QOpenGLFramebufferObject::CombinedDepthStencil);
m_quickWindow->setRenderTarget(m_fbo.get());

E tramite questo possiamo cominciare il rendering ma c’è un limite – non possiamo ancora calcolare a frame rate personalizzati, siccome, come ho detto prima (e questo è esattamente quello che il blog che ho precedentemente menzionato tenta principalmente di spiegare). Per raggiungere questo obiettivo, dobbiamo modificare il driver dell’animazione: creiamo il nostro driver di animazione e avanziamo tra i fotogrammi al ritmo scelto:

void advance() override
{
m_elapsed += m_step;
advanceAnimation();
}

Con questo, e le 4 linee successive (ovviamente in un loop guidato dagli eventi)

m_renderControl->polishItems();
m_renderControl->sync();
m_renderControl->render();
m_context->functions()->glFlush();

Ora stai calcolando i fotogrammi! (se vuoi vedere il codice dai un’occhiata a root/QmlRenderer/src/)

Questo è il funzionamento – tramite il mio lavoro fino ad ora, ho scritto il codice sopra menzionato quasi pronto per la produzione.

Per la prossima settimana ho già iniziato a scrivere un test unificato per essere sicuri  che la libreria lavori corretamente in qualsiasi fase nel futuro. E dopo questo, comincerò a smanettare su MLT per scrivere un producer.

A questo punto immagino vi sarete posti questa domanda: perché sviluppare una libreria indipendente? Perché non integrare il codice direttamente in MLT?

Perché
a) Modularità : è più facile testare un pezzo di codice indipendente e assicurarsi che funzioni.
b) Integrazione facile: è più facile integrare un modulo con un framework – visto ché ci sono discussioni sul futuro di MLT in Kdenlive.

Questo è tutto per la settimana. Speriamo in meglio!

 

 

Traduzione dell’articolo di