Estoy intentando resolver lo que pensé que sería un problema muy simple. Quiero mantener un QPixmap actualizado con todo el contenido de la pantalla. Usted puede obtener un mapa de pixels tal al hacer esto:Mantener copia de QPixmap del contenido de la pantalla usando X11, XDamage, XRender y otros trucos
QDesktopWidget *w = QApplication::desktop();
if (w)
{
QRect r = w->screenGeometry();
QPixmap p = QPixmap::grabWindow(w->winId(), 0, 0, r.width(), r.height())
QByteArray bitmap;
}
El problema con esto es que QDesktopWidget termina por volver a agarrar todo el mapa de píxeles de la pantalla desde el servidor X11 cada vez que lo solicita, aunque nada ha cambiado.
Necesito este código para ser rápido, así que estoy tratando de hacer esto por mí mismo. Mi punto de partida fue el qx11mirror demo, sin embargo, básicamente hace lo mismo. Utiliza la extensión XDamage para funcionar cuando algo ha cambiado, pero en lugar de utilizar la información del rectángulo dañado para actualizar solo esa parte del mapa de píxeles en caché, simplemente establece un indicador "sucio", que de todos modos activa una actualización completa.
Intento modificar el ejemplo de qx11mirror para actualizar la parte dañada de las ventanas, pero parece que no puedo hacer nada, todo lo que obtengo es un mapa de píxeles en blanco (negro). El código que estoy usando es:
void QX11Mirror::x11Event(XEvent *event)
{
if (event->type == m_damageEvent + XDamageNotify)
{
XDamageNotifyEvent *e = reinterpret_cast<XDamageNotifyEvent*>(event);
XWindowAttributes attr;
XGetWindowAttributes(QX11Info::display(), m_window, &attr);
XRenderPictFormat *format = XRenderFindVisualFormat(QX11Info::display(), attr.visual);
bool hasAlpha = (format->type == PictTypeDirect && format->direct.alphaMask);
int x = attr.x;
int y = attr.y;
int width = attr.width;
int height = attr.height;
// debug output so I can see the window pos vs the damaged area:
qDebug() << "repainting dirty area:" << x << y << width << height << "vs" << e->area.x << e->area.y << e->area.width << e->area.height;
XRenderPictureAttributes pa;
pa.subwindow_mode = IncludeInferiors; // Don't clip child widgets
Picture picture = XRenderCreatePicture(QX11Info::display(),
m_window,
format,
CPSubwindowMode,
&pa);
XserverRegion region = XFixesCreateRegionFromWindow(QX11Info::display(),
m_window, WindowRegionBounding);
XFixesTranslateRegion(QX11Info::display(), region, -x, -y);
XFixesSetPictureClipRegion(QX11Info::display(), picture, 0, 0, region);
XFixesDestroyRegion(QX11Info::display(), region);
//QPixmap dest(width, height);
XRenderComposite(QX11Info::display(), // display
hasAlpha ? PictOpOver : PictOpSrc, // operation mode
picture, // src drawable
None, // src mask
dest.x11PictureHandle(), // dest drawable
e->area.x, // src X
e->area.y, // src Y
0, // mask X
0, // mask Y
e->area.x, // dest X
e->area.y, // dest Y
e->area.width, // width
e->area.height); // height
m_px = dest;
XDamageSubtract(QX11Info::display(), e->damage, None, None);
emit windowChanged();
}
else if (event->type == ConfigureNotify)
{
XConfigureEvent *e = &event->xconfigure;
m_position = QRect(e->x, e->y, e->width, e->height);
emit positionChanged(m_position);
}
}
¿Alguien puede señalarme en la dirección correcta? La documentación para XRender, XDamage y las otras extensiones X11 es bastante mala.
Razones para utilizar XRender sobre XCopyArea
El siguiente texto tomado de here.
Es posible crear un GC para una ventana y usar XCopyArea() para copiar el contenido de la ventana si desea usar el protocolo central, pero dado que la extensión Composite expone visuales nuevos (con canales alfa, por ejemplo), no hay garantía de que el formato de la fuente dibujable coincida con el del destino. Con el protocolo central esa situación dará como resultado un error de coincidencia, algo que no sucederá con la extensión de Xrender.
Además, el protocolo central no comprende los canales alfa, lo que significa que no puede componer ventanas que usan la nueva visualización ARGB. Cuando la fuente y el destino tienen el mismo formato, tampoco hay ventaja de rendimiento al usar el protocolo central a partir de X11R6.8. Esa versión también es la primera en admitir la nueva extensión compuesta.
Por lo tanto, en conclusión, no hay inconvenientes, y solo ventajas de elegir Xrender sobre el protocolo central para estas operaciones.
¿Por qué utilizar XRender en lugar de XCopyArea? XRender es propenso a errores (si no lo haces exactamente de la manera correcta, no funcionará). – ypnos
Descubrí que intentar actualizar la pantalla solo actualizando las piezas dañadas no funciona tan bien en la práctica. Por ejemplo, las aplicaciones OpenGL nunca parecen informar daños. Creo que tu mejor opción es seguir recapturando la pantalla. – ldog
Puede volver a capturar la pantalla casi en tiempo real (10-20 fotogramas por segundo) si lo hace de manera inteligente. – ldog