X11, XDAMAGE, XRENDER 및 기타 트릭을 사용하여 스크린 내용의 QPIXMAP 사본을 유지하십시오.

StackOverflow https://stackoverflow.com/questions/1427711

  •  07-07-2019
  •  | 
  •  

문제

나는 매우 간단한 문제라고 생각한 것을 해결하려고 노력하고 있습니다. 전체 화면 내용으로 qpixmap을 업데이트하고 싶습니다. 이 작업을 수행하여 PIXMAP을 얻을 수 있습니다.

QDesktopWidget *w = QApplication::desktop();
if (w)
{
    QRect r = w->screenGeometry();
    QPixmap p = QPixmap::grabWindow(w->winId(), 0, 0, r.width(), r.height())
    QByteArray bitmap;
}

이것의 문제점은 qdesktopwidget이 아무것도 변경되지 않았더라도 요청할 때마다 x11 서버에서 전체 화면 pixmap을 다시 잡는다는 것입니다.

이 코드가 빠르려면이 코드가 필요하므로 직접 수행하려고합니다. 내 출발점은 qx11mirror 데모, 그러나 기본적으로 같은 일을합니다. Xdamage 확장을 사용하여 무언가가 변경되었을 때 해결되지만 손상된 사각형 정보를 사용하여 캐시 된 PixMap의 해당 부분 만 업데이트하는 대신 "더러운"플래그를 설정하여 어쨌든 전체 새로 고침을 트리거합니다.

그래서 저는 QX11Mirror 예제를 수정하여 Windows의 손상된 부분을 업데이트하려고하지만 작업 할 작업을 얻을 수는 없습니다. 공백 (검은 색) Pixmap입니다. 내가 사용하는 코드는 다음과 같습니다.

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);
    }
}

누구든지 나를 올바른 방향으로 가리킬 수 있습니까? Xrender, Xdamage 및 기타 X11 확장에 대한 문서화는 꽤 나쁩니다.

XcopyArea를 통해 Xrender를 사용하는 이유

다음 텍스트에서 가져온 텍스트 여기.

핵심 프로토콜을 사용하려는 경우 창에 GC를 생성하고 XcopyArea ()를 사용하여 창의 내용을 복사하는 것이 가능하지만 복합 확장이 새로운 비주얼 (예 : 알파 채널이있는 것)을 노출시키기 때문에 없습니다. 소스 드로우 가능의 형식이 대상의 형식과 일치하도록 보장합니다. 핵심 프로토콜을 사용하면 해당 상황이 일치 오류가 발생합니다. Xrender 확장에서는 발생하지 않습니다.

또한 핵심 프로토콜은 알파 채널을 이해하지 못하므로 새로운 ArgB Visual을 사용하는 Windows를 합성 할 수 없습니다. 소스와 대상이 동일한 형식을 갖는 경우 X11R6.8의 핵심 프로토콜을 사용하는 데는 성능 이점이 없습니다. 이 릴리스는 또한 새로운 복합 확장을 지원하는 최초의 릴리스입니다.

따라서 결론적으로 단점은 없으며 이러한 작업의 핵심 프로토콜을 통해 Xrender를 선택하는 데있어 장점 만 있습니다.

도움이 되었습니까?

해결책

먼저 qx11mirror :: setwindow에서 xdamagereportBoundingbox로 DamageCreate를 호출 할 때 DamagerePortLevel을 변경해야합니다.

다음으로 xrendercomposite로 호출하기 전에 dest.detach ()를 호출해야합니다. M_PX와 DEST를 모두 멤버 변수로 모두 필요하지 않습니다. M__PX 만 사용할 수 있습니다.

이 예에서 XrenderFreepicture에 대한 통화가 누락되어 XRenderComposite에 대한 호출 이후에 가야합니다.

XRenderFreePicture(QX11Info::display(), picture);

qx11mirror :: x11event의 모든 코드 qx11mirror :: pixmap을 복제 할 필요는 없습니다. 대신 m_dirty 유형을 bool에서 qrect로 변경 한 다음 xdamagenotifyevent (예 : e-> 영역의 사각형으로 m_dirty를 업데이트하십시오. 그런 다음 qx11mirror : pixmap에서 m_dirty가 진실인지 확인하기보다는 m_dirty가 빈 사각형이 아닌지 확인하십시오. 그런 다음 사각형을 m_dirty에서 xrendercomposite로 전달합니다.

편집하다:

dest.detach는 핵심 비트입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top