Exemplo n.º 1
0
void EglOnXBackend::present()
{
    if (lastDamage().isEmpty())
        return;

    const QRegion displayRegion(0, 0, displayWidth(), displayHeight());
    const bool fullRepaint = supportsBufferAge() || (lastDamage() == displayRegion);

    if (fullRepaint || !surfaceHasSubPost) {
        if (gs_tripleBufferNeedsDetection) {
            eglWaitGL();
            m_swapProfiler.begin();
        }
        // the entire screen changed, or we cannot do partial updates (which implies we enabled surface preservation)
        eglSwapBuffers(dpy, surface);
        if (gs_tripleBufferNeedsDetection) {
            eglWaitGL();
            if (char result = m_swapProfiler.end()) {
                gs_tripleBufferUndetected = gs_tripleBufferNeedsDetection = false;
                if (result == 'd' && GLPlatform::instance()->driver() == Driver_NVidia) {
                    // TODO this is a workaround, we should get __GL_YIELD set before libGL checks it
                    if (qstrcmp(qgetenv("__GL_YIELD"), "USLEEP")) {
                        options->setGlPreferBufferSwap(0);
                        eglSwapInterval(dpy, 0);
                        qWarning() << "\nIt seems you are using the nvidia driver without triple buffering\n"
                                          "You must export __GL_YIELD=\"USLEEP\" to prevent large CPU overhead on synced swaps\n"
                                          "Preferably, enable the TripleBuffer Option in the xorg.conf Device\n"
                                          "For this reason, the tearing prevention has been disabled.\n"
                                          "See https://bugs.kde.org/show_bug.cgi?id=322060\n";
                    }
                }
                setBlocksForRetrace(result == 'd');
            }
        }
        if (supportsBufferAge()) {
            eglQuerySurface(dpy, surface, EGL_BUFFER_AGE_EXT, &m_bufferAge);
        }
    } else {
        // a part of the screen changed, and we can use eglPostSubBufferNV to copy the updated area
        foreach (const QRect & r, lastDamage().rects()) {
            eglPostSubBufferNV(dpy, surface, r.left(), displayHeight() - r.bottom() - 1, r.width(), r.height());
        }
    }

    setLastDamage(QRegion());
    if (!supportsBufferAge()) {
        eglWaitGL();
        xcb_flush(connection());
    }
}
Exemplo n.º 2
0
void GlxBackend::present()
{
    if (lastDamage().isEmpty())
        return;

    const QRegion displayRegion(0, 0, displayWidth(), displayHeight());
    const bool fullRepaint = supportsBufferAge() || (lastDamage() == displayRegion);

    if (fullRepaint) {
        if (haveSwapInterval) {
            if (gs_tripleBufferNeedsDetection) {
                glXWaitGL();
                m_swapProfiler.begin();
            }
            glXSwapBuffers(display(), glxWindow);
            if (gs_tripleBufferNeedsDetection) {
                glXWaitGL();
                if (char result = m_swapProfiler.end()) {
                    gs_tripleBufferUndetected = gs_tripleBufferNeedsDetection = false;
                    if (result == 'd' && GLPlatform::instance()->driver() == Driver_NVidia) {
                        // TODO this is a workaround, we should get __GL_YIELD set before libGL checks it
                        if (qstrcmp(qgetenv("__GL_YIELD"), "USLEEP")) {
                            options->setGlPreferBufferSwap(0);
                            setSwapInterval(0);
                            qWarning() << "\nIt seems you are using the nvidia driver without triple buffering\n"
                                              "You must export __GL_YIELD=\"USLEEP\" to prevent large CPU overhead on synced swaps\n"
                                              "Preferably, enable the TripleBuffer Option in the xorg.conf Device\n"
                                              "For this reason, the tearing prevention has been disabled.\n"
                                              "See https://bugs.kde.org/show_bug.cgi?id=322060\n";
                        }
                    }
                    setBlocksForRetrace(result == 'd');
                }
            }
        } else {
            waitSync();
            glXSwapBuffers(display(), glxWindow);
        }
        if (supportsBufferAge()) {
            glXQueryDrawable(display(), glxWindow, GLX_BACK_BUFFER_AGE_EXT, (GLuint *) &m_bufferAge);
        }
    } else if (glXCopySubBuffer) {
        foreach (const QRect & r, lastDamage().rects()) {
            // convert to OpenGL coordinates
            int y = displayHeight() - r.y() - r.height();
            glXCopySubBuffer(display(), glxWindow, r.x(), y, r.width(), r.height());
        }
    } else { // Copy Pixels (horribly slow on Mesa)
Exemplo n.º 3
0
void LogoutEffect::reconfigure( ReconfigureFlags )
    {
    // Disable blur by default as some drivers don't correctly fallback if they don't
    // support it and I have yet to work out a way of accurately detecting support.
    KConfigGroup conf = effects->effectConfig( "Logout" );
    bool useBlur = conf.readEntry( "UseBlur", false );

#ifdef KWIN_HAVE_OPENGL_COMPOSITING
    blurSupported = false;
    blurTexture = NULL;
    blurTarget = NULL;
    if( effects->compositingType() == OpenGLCompositing && GLTexture::NPOTTextureSupported() && useBlur )
        { // TODO: It seems that it is not possible to create a GLRenderTarget that has
          //       a different size than the display right now. Most likely a KWin core bug.
        // Create texture and render target
        blurTexture = new GLTexture( displayWidth(), displayHeight() );
        blurTexture->setFilter( GL_LINEAR_MIPMAP_LINEAR );
        blurTexture->setWrapMode( GL_CLAMP_TO_EDGE );

        blurTarget = new GLRenderTarget( blurTexture );
        if( blurTarget->valid() )
            blurSupported = true;
        }
#endif
    }
Exemplo n.º 4
0
void VideoRecordEffect::paintScreen( int mask, QRegion region, ScreenPaintData& data )
    {
    effects->paintScreen( mask, region, data );
    if( client != NULL )
        capture_region = ( mask & ( PAINT_WINDOW_TRANSFORMED | PAINT_SCREEN_TRANSFORMED ))
            ? QRect( 0, 0, displayWidth(), displayHeight()) : region;
    }
Exemplo n.º 5
0
void ScreenEdge::switchDesktop(ElectricBorder border, const QPoint& _pos)
{
    QPoint pos = _pos;
    int desk = Workspace::self()->currentDesktop();
    const int OFFSET = 2;
    if (border == ElectricLeft || border == ElectricTopLeft || border == ElectricBottomLeft) {
        desk = Workspace::self()->desktopToLeft(desk, options->isRollOverDesktops());
        pos.setX(displayWidth() - 1 - OFFSET);
    }
    if (border == ElectricRight || border == ElectricTopRight || border == ElectricBottomRight) {
        desk = Workspace::self()->desktopToRight(desk, options->isRollOverDesktops());
        pos.setX(OFFSET);
    }
    if (border == ElectricTop || border == ElectricTopLeft || border == ElectricTopRight) {
        desk = Workspace::self()->desktopAbove(desk, options->isRollOverDesktops());
        pos.setY(displayHeight() - 1 - OFFSET);
    }
    if (border == ElectricBottom || border == ElectricBottomLeft || border == ElectricBottomRight) {
        desk = Workspace::self()->desktopBelow(desk, options->isRollOverDesktops());
        pos.setY(OFFSET);
    }
    Client *c = Workspace::self()->getMovingClient();
    if (c && c->rules()->checkDesktop(desk) != desk)
        return; // user attempts to move a client to another desktop where it is ruleforced to not be
    int desk_before = Workspace::self()->currentDesktop();
    Workspace::self()->setCurrentDesktop(desk);
    if (Workspace::self()->currentDesktop() != desk_before)
        QCursor::setPos(pos);
}
Exemplo n.º 6
0
// Create the compositing buffer. The root window is not double-buffered,
// so it is done manually using this buffer,
void SceneXrender::createBuffer()
{
    if (buffer != None)
        XRenderFreePicture(display(), buffer);
    Pixmap pixmap = XCreatePixmap(display(), rootWindow(), displayWidth(), displayHeight(), DefaultDepth(display(), DefaultScreen(display())));
    buffer = XRenderCreatePicture(display(), pixmap, format, 0, 0);
    XFreePixmap(display(), pixmap);   // The picture owns the pixmap now
}
Exemplo n.º 7
0
void X11XRenderBackend::present(int mask, const QRegion &damage)
{
    if (mask & Scene::PAINT_SCREEN_REGION) {
        // Use the damage region as the clip region for the root window
        XFixesRegion frontRegion(damage);
        xcb_xfixes_set_picture_clip_region(connection(), m_front, frontRegion, 0, 0);
        // copy composed buffer to the root window
        xcb_xfixes_set_picture_clip_region(connection(), buffer(), XCB_XFIXES_REGION_NONE, 0, 0);
        xcb_render_composite(connection(), XCB_RENDER_PICT_OP_SRC, buffer(), XCB_RENDER_PICTURE_NONE,
                             m_front, 0, 0, 0, 0, 0, 0, displayWidth(), displayHeight());
        xcb_xfixes_set_picture_clip_region(connection(), m_front, XCB_XFIXES_REGION_NONE, 0, 0);
        xcb_flush(connection());
    } else {
        // copy composed buffer to the root window
        xcb_render_composite(connection(), XCB_RENDER_PICT_OP_SRC, buffer(), XCB_RENDER_PICTURE_NONE,
                             m_front, 0, 0, 0, 0, 0, 0, displayWidth(), displayHeight());
        xcb_flush(connection());
    }
}
Exemplo n.º 8
0
VideoRecordEffect::VideoRecordEffect()
    : client( NULL )
    {
    KActionCollection* actionCollection = new KActionCollection( this );
    KAction* a = static_cast< KAction* >( actionCollection->addAction( "VideoRecord" ));
    a->setText( i18n("Toggle Video Recording" ));
    a->setGlobalShortcut( KShortcut( Qt::CTRL + Qt::META + Qt::Key_V ));
    connect( a, SIGNAL( triggered( bool )), this, SLOT( toggleRecording()));
    area = QRect( 0, 0, displayWidth(), displayHeight());
    }
Exemplo n.º 9
0
void VideoRecordEffect::postPaintScreen()
    {
    effects->postPaintScreen();
    if( client != NULL )
        {
#if 1
        if( CapturyProcessRegionStart( client ) == CAPTURY_SUCCESS )
            {
            capture_region &= QRect( 0, 0, displayWidth(), displayHeight()); // limit to screen
            foreach( const QRect &r, capture_region.rects())
                {
                int gly = displayHeight() - r.y() - r.height(); // opengl coords
                CapturyProcessRegion( client, r.x(), gly, r.width(), r.height());
                }
            CapturyProcessRegionCommit( client );
            }
#else
        CapturyProcessFrame( client );
#endif
        }
Exemplo n.º 10
0
void LogoutEffect::paintScreen( int mask, QRegion region, ScreenPaintData& data )
    {
    effects->paintScreen( mask, region, data );

#ifdef KWIN_HAVE_OPENGL_COMPOSITING
    if( blurSupported && progress > 0.0 )
        {
        assert( effects->popRenderTarget() == blurTarget );

        // Render the blurred scene
        blurTexture->bind();
        GLfloat bias[1];
        glGetTexEnvfv( GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, bias );
        glTexEnvf( GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, progress * 2.75 );
        glBegin( GL_QUADS );
            glTexCoord2f( 0.0, 0.0 );
            glVertex2f( 0.0, displayHeight() );
            glTexCoord2f( 1.0, 0.0 );
            glVertex2f( displayWidth(), displayHeight() );
            glTexCoord2f( 1.0, 1.0 );
            glVertex2f( displayWidth(), 0.0 );
            glTexCoord2f( 0.0, 1.0 );
            glVertex2f( 0.0, 0.0 );
        glEnd();
        glTexEnvf( GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, bias[0] );
        blurTexture->unbind();

        // Render the logout window
        if( logoutWindow )
            {
            int winMask = logoutWindow->hasAlpha() ? PAINT_WINDOW_TRANSLUCENT : PAINT_WINDOW_OPAQUE;
            WindowPaintData winData( logoutWindow );
            winData.opacity = windowOpacity;
            effects->drawWindow( logoutWindow, winMask, region, winData );
            }
        }
#endif
    }
Exemplo n.º 11
0
void ScreenEdge::update(bool force)
{
    m_screenEdgeTimeFirst = xTime();
    m_screenEdgeTimeLast = xTime();
    m_screenEdgeTimeLastTrigger = xTime();
    m_currentScreenEdge = ElectricNone;
    QRect r = QRect(0, 0, displayWidth(), displayHeight());
    m_screenEdgeTop = r.top();
    m_screenEdgeBottom = r.bottom();
    m_screenEdgeLeft = r.left();
    m_screenEdgeRight = r.right();

    for (int pos = 0; pos < ELECTRIC_COUNT; ++pos) {
        if (force || m_screenEdgeReserved[pos] == 0) {
            if (m_screenEdgeWindows[pos] != None)
                XDestroyWindow(display(), m_screenEdgeWindows[pos]);
            m_screenEdgeWindows[pos] = None;
        }
        if (m_screenEdgeReserved[pos] == 0) {
            continue;
        }
        if (m_screenEdgeWindows[pos] != None)
            continue;
        XSetWindowAttributes attributes;
        attributes.override_redirect = True;
        attributes.event_mask = EnterWindowMask | LeaveWindowMask;
        unsigned long valuemask = CWOverrideRedirect | CWEventMask;
        int xywh[ELECTRIC_COUNT][4] = {
            { r.left() + 1, r.top(), r.width() - 2, 1 },   // Top
            { r.right(), r.top(), 1, 1 },                  // Top-right
            { r.right(), r.top() + 1, 1, r.height() - 2 }, // Etc.
            { r.right(), r.bottom(), 1, 1 },
            { r.left() + 1, r.bottom(), r.width() - 2, 1 },
            { r.left(), r.bottom(), 1, 1 },
            { r.left(), r.top() + 1, 1, r.height() - 2 },
            { r.left(), r.top(), 1, 1 }
        };
        m_screenEdgeWindows[pos] = XCreateWindow(display(), rootWindow(),
                                              xywh[pos][0], xywh[pos][1], xywh[pos][2], xywh[pos][3],
                                              0, CopyFromParent, InputOnly, CopyFromParent, valuemask, &attributes);
        XMapWindow(display(), m_screenEdgeWindows[pos]);

        // Set XdndAware on the windows, so that DND enter events are received (#86998)
        Atom version = 4; // XDND version
        XChangeProperty(display(), m_screenEdgeWindows[pos], atoms->xdnd_aware, XA_ATOM,
                        32, PropModeReplace, (unsigned char*)(&version), 1);
    }
}
Exemplo n.º 12
0
void LogoutEffect::prePaintScreen(ScreenPrePaintData& data, int time)
{
    if (!displayEffect && progress == 0.0) {
        if (blurTexture) {
            delete blurTexture;
            blurTexture = NULL;
            delete blurTarget;
            blurTarget = NULL;
            blurSupported = false;
        }
    } else if (!blurTexture) {
        blurSupported = false;
        delete blurTarget; // catch as we just tested the texture ;-P
        if (effects->compositingType() == OpenGLCompositing && GLTexture::NPOTTextureSupported() && GLRenderTarget::blitSupported() && useBlur) {
            // TODO: It seems that it is not possible to create a GLRenderTarget that has
            //       a different size than the display right now. Most likely a KWin core bug.
            // Create texture and render target
            blurTexture = new GLTexture(displayWidth(), displayHeight());
            blurTexture->setFilter(GL_LINEAR_MIPMAP_LINEAR);
            blurTexture->setWrapMode(GL_CLAMP_TO_EDGE);

            blurTarget = new GLRenderTarget(*blurTexture);
            if (blurTarget->valid())
                blurSupported = true;

            // As creating the render target takes time it can cause the first two frames of the
            // blur animation to be jerky. For this reason we only start the animation after the
            // third frame.
            frameDelay = 2;
        }
    }

    if (frameDelay)
        --frameDelay;
    else {
        if (displayEffect)
            progress = qMin(1.0, progress + time / animationTime(2000.0));
        else if (progress > 0.0)
            progress = qMax(0.0, progress - time / animationTime(500.0));
    }

    if (blurSupported && progress > 0.0) {
        data.mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS;
    }

    effects->prePaintScreen(data, time);
}
Exemplo n.º 13
0
void ScreenEdge::restoreSize(ElectricBorder border)
{
    if (m_screenEdgeWindows[border] == None)
        return;
    QRect r(0, 0, displayWidth(), displayHeight());
    int xywh[ELECTRIC_COUNT][4] = {
        { r.left() + 1, r.top(), r.width() - 2, 1 },   // Top
        { r.right(), r.top(), 1, 1 },                  // Top-right
        { r.right(), r.top() + 1, 1, r.height() - 2 }, // Etc.
        { r.right(), r.bottom(), 1, 1 },
        { r.left() + 1, r.bottom(), r.width() - 2, 1 },
        { r.left(), r.bottom(), 1, 1 },
        { r.left(), r.top() + 1, 1, r.height() - 2 },
        { r.left(), r.top(), 1, 1 }
    };
    XMoveResizeWindow(display(), m_screenEdgeWindows[border],
                      xywh[border][0], xywh[border][1], xywh[border][2], xywh[border][3]);
}
Exemplo n.º 14
0
void LanczosFilter::updateOffscreenSurfaces()
{
    int w = displayWidth();
    int h = displayHeight();
    if (!GLTexture::NPOTTextureSupported()) {
        w = nearestPowerOfTwo(w);
        h = nearestPowerOfTwo(h);
    }
    if (!m_offscreenTex || m_offscreenTex->width() != w || m_offscreenTex->height() != h) {
        if (m_offscreenTex) {
            delete m_offscreenTex;
            delete m_offscreenTarget;
        }
        m_offscreenTex = new GLTexture(w, h);
        m_offscreenTex->setFilter(GL_LINEAR);
        m_offscreenTex->setWrapMode(GL_CLAMP_TO_EDGE);
        m_offscreenTarget = new GLRenderTarget(*m_offscreenTex);
    }
}
Exemplo n.º 15
0
// create destination buffer
bool SceneOpenGL::initBuffer()
{
    if (!initBufferConfigs())
        return false;
    if (fbcbuffer_db != NULL && m_overlayWindow->create()) {
        // we have overlay, try to create double-buffered window in it
        fbcbuffer = fbcbuffer_db;
        XVisualInfo* visual = glXGetVisualFromFBConfig(display(), fbcbuffer);
        XSetWindowAttributes attrs;
        attrs.colormap = XCreateColormap(display(), rootWindow(), visual->visual, AllocNone);
        buffer = XCreateWindow(display(), m_overlayWindow->window(), 0, 0, displayWidth(), displayHeight(),
                               0, visual->depth, InputOutput, visual->visual, CWColormap, &attrs);
        if (hasGLXVersion(1, 3))
            glxbuffer = glXCreateWindow(display(), fbcbuffer, buffer, NULL);
        else
            glxbuffer = buffer;
        m_overlayWindow->setup(buffer);
        db = true;
        XFree(visual);
    } else if (fbcbuffer_nondb != NULL) {
        // cannot get any double-buffered drawable, will double-buffer using a pixmap
        fbcbuffer = fbcbuffer_nondb;
        XVisualInfo* visual = glXGetVisualFromFBConfig(display(), fbcbuffer);
        XGCValues gcattr;
        gcattr.subwindow_mode = IncludeInferiors;
        gcroot = XCreateGC(display(), rootWindow(), GCSubwindowMode, &gcattr);
        buffer = XCreatePixmap(display(), rootWindow(), displayWidth(), displayHeight(),
                               visual->depth);
        glxbuffer = glXCreatePixmap(display(), fbcbuffer, buffer, NULL);
        db = false;
        XFree(visual);
    } else {
        kError(1212) << "Couldn't create output buffer (failed to create overlay window?) !";
        return false; // error
    }
    int vis_buffer;
    glXGetFBConfigAttrib(display(), fbcbuffer, GLX_VISUAL_ID, &vis_buffer);
    XVisualInfo* visinfo_buffer = glXGetVisualFromFBConfig(display(), fbcbuffer);
    kDebug(1212) << "Buffer visual (depth " << visinfo_buffer->depth << "): 0x" << QString::number(vis_buffer, 16);
    XFree(visinfo_buffer);
    return true;
}
Exemplo n.º 16
0
void MinimizeAnimationEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
    {
    if( mTimeLineWindows.contains( w ))
    {
        // 0 = not minimized, 1 = fully minimized
        double progress = mTimeLineWindows[w].value();

        QRect geo = w->geometry();
        QRect icon = w->iconGeometry();
        // If there's no icon geometry, minimize to the center of the screen
        if( !icon.isValid() )
            icon = QRect( displayWidth() / 2, displayHeight() / 2, 0, 0 );

        data.xScale *= interpolate(1.0, icon.width() / (double)geo.width(), progress);
        data.yScale *= interpolate(1.0, icon.height() / (double)geo.height(), progress);
        data.xTranslate = (int)interpolate(data.xTranslate, icon.x() - geo.x(), progress);
        data.yTranslate = (int)interpolate(data.yTranslate, icon.y() - geo.y(), progress);
        data.opacity *= 0.1 + (1-progress)*0.9;
    }

    // Call the next effect.
    effects->paintWindow( w, mask, region, data );
    }
Exemplo n.º 17
0
        // whole screen, not transformed, force region to be full
        *region = QRegion(0, 0, displayWidth(), displayHeight());
    }
    painted_region = *region;
    if (*mask & PAINT_SCREEN_BACKGROUND_FIRST) {
        paintBackground(*region);
    }
    ScreenPaintData data;
    effects->paintScreen(*mask, *region, data);
    foreach (Window * w, stacking_order) {
        effects->postPaintWindow(effectWindow(w));
    }
    effects->postPaintScreen();
    *region |= painted_region;
    // make sure not to go outside of the screen area
    *region &= QRegion(0, 0, displayWidth(), displayHeight());
    // make sure all clipping is restored
    Q_ASSERT(!PaintClipper::clip());
}

// Compute time since the last painting pass.
void Scene::updateTimeDiff()
{
    if (!last_time.isValid()) {
        // Painting has been idle (optimized out) for some time,
        // which means time_diff would be huge and would break animations.
        // Simply set it to one (zero would mean no change at all and could
        // cause problems).
        time_diff = 1;
        last_time.start();
    } else
Exemplo n.º 18
0
// Create the compositing buffer. The root window is not double-buffered,
// so it is done manually using this buffer,
void SceneXrender::createBuffer()
{
    if (buffer != XCB_RENDER_PICTURE_NONE)
        xcb_render_free_picture(connection(), buffer);
    xcb_pixmap_t pixmap = xcb_generate_id(connection());
    xcb_create_pixmap(connection(), Xcb::defaultDepth(), pixmap, rootWindow(), displayWidth(), displayHeight());
    buffer = xcb_generate_id(connection());
    xcb_render_create_picture(connection(), buffer, pixmap, format, 0, NULL);
    xcb_free_pixmap(connection(), pixmap);   // The picture owns the pixmap now
}
Exemplo n.º 19
0
bool GlxBackend::initBuffer()
{
    if (!initFbConfig())
        return false;

    if (overlayWindow()->create()) {
        // Try to create double-buffered window in the overlay
        XVisualInfo* visual = glXGetVisualFromFBConfig(display(), fbconfig);
        if (!visual) {
           qCritical() << "Failed to get visual from fbconfig";
           return false;
        }
        XSetWindowAttributes attrs;
        attrs.colormap = XCreateColormap(display(), rootWindow(), visual->visual, AllocNone);
        window = XCreateWindow(display(), overlayWindow()->window(), 0, 0, displayWidth(), displayHeight(),
                               0, visual->depth, InputOutput, visual->visual, CWColormap, &attrs);
        glxWindow = glXCreateWindow(display(), fbconfig, window, NULL);
        overlayWindow()->setup(window);
        XFree(visual);
    } else {
        qCritical() << "Failed to create overlay window";
        return false;
    }

    int vis_buffer;
    glXGetFBConfigAttrib(display(), fbconfig, GLX_VISUAL_ID, &vis_buffer);
    XVisualInfo* visinfo_buffer = glXGetVisualFromFBConfig(display(), fbconfig);
    qDebug() << "Buffer visual (depth " << visinfo_buffer->depth << "): 0x" << QString::number(vis_buffer, 16);
    XFree(visinfo_buffer);

    return true;
}
Exemplo n.º 20
0
// Gives a position of the given desktop when all desktops are arranged in a grid
QRect SlideEffect::desktopRect( int desktop ) const
    {
    QRect rect( 0, 0, displayWidth(), displayHeight() );
    rect.translate( effects->desktopCoords( desktop ));
    return rect;
    }
Exemplo n.º 21
0
Window EffectsHandler::createFullScreenInputWindow(Effect* e, const QCursor& cursor)
{
    return createInputWindow(e, 0, 0, displayWidth(), displayHeight(), cursor);
}
Exemplo n.º 22
0
void BlurEffect::doCachedBlur(EffectWindow *w, const QRegion& region, const float opacity)
{
    const QRect screen = effects->virtualScreenGeometry();
    const QRegion blurredRegion = blurRegion(w).translated(w->pos()) & screen;
    const QRegion expanded = expand(blurredRegion) & screen;
    const QRect r = expanded.boundingRect();

    // The background texture we get is only partially valid.

    CacheEntry it = windows.find(w);
    if (it == windows.end()) {
        BlurWindowInfo bwi;
        bwi.blurredBackground = GLTexture(r.width(),r.height());
        bwi.damagedRegion = expanded;
        bwi.dropCache = false;
        bwi.windowPos = w->pos();
        it = windows.insert(w, bwi);
    } else if (it->blurredBackground.size() != r.size()) {
        it->blurredBackground = GLTexture(r.width(),r.height());
        it->dropCache = false;
        it->windowPos = w->pos();
    } else if (it->windowPos != w->pos()) {
        it->dropCache = false;
        it->windowPos = w->pos();
    }

    GLTexture targetTexture = it->blurredBackground;
    targetTexture.setFilter(GL_LINEAR);
    targetTexture.setWrapMode(GL_CLAMP_TO_EDGE);
    shader->bind();
    QMatrix4x4 textureMatrix;
    QMatrix4x4 modelViewProjectionMatrix;

    /**
     * Which part of the background texture can be updated ?
     *
     * Well this is a rather difficult question. We kind of rely on the fact, that
     * we need a bigger background region being painted before, more precisely if we want to
     * blur region A we need the background region expand(A). This business logic is basically
     * done in prePaintWindow:
     *          data.paint |= expand(damagedArea);
     *
     * Now "data.paint" gets clipped and becomes what we receive as the "region" variable
     * in this function. In theory there is now only one function that does this clipping
     * and this is paintSimpleScreen. The clipping has the effect that "damagedRegion"
     * is no longer a subset of "region" and we cannot fully validate the cache within one
     * rendering pass. If we would now update the "damageRegion & region" part of the cache
     * we would wrongly update the part of the cache that is next to the "region" border and
     * which lies within "damagedRegion", just because we cannot assume that the framebuffer
     * outside of "region" is valid. Therefore the maximal damaged region of the cache that can
     * be repainted is given by:
     *          validUpdate = damagedRegion - expand(damagedRegion - region);
     *
     * Now you may ask what is with the rest of "damagedRegion & region" that is not part
     * of "validUpdate" but also might end up on the screen. Well under the assumption
     * that only the occlusion culling can shrink "data.paint", we can control this by reducing
     * the opaque area of every window by a margin of the blurring radius (c.f. prePaintWindow).
     * This way we are sure that this area is overpainted by a higher opaque window.
     *
     * Apparently paintSimpleScreen is not the only function that can influence "region".
     * In fact every effect's paintWindow that is called before Blur::paintWindow
     * can do so (e.g. SlidingPopups). Hence we have to make the compromise that we update
     * "damagedRegion & region" of the cache but only mark "validUpdate" as valid.
     **/
    const QRegion damagedRegion = it->damagedRegion;
    const QRegion updateBackground = damagedRegion & region;
    const QRegion validUpdate = damagedRegion - expand(damagedRegion - region);

    const QRegion horizontal = validUpdate.isEmpty() ? QRegion() : (updateBackground & screen);
    const QRegion vertical   = blurredRegion & region;

    const int horizontalOffset = 0;
    const int horizontalCount = horizontal.rectCount() * 6;

    const int verticalOffset = horizontalCount;
    const int verticalCount = vertical.rectCount() * 6;

    GLVertexBuffer *vbo = GLVertexBuffer::streamingBuffer();
    uploadGeometry(vbo, horizontal, vertical);

    vbo->bindArrays();

    if (!validUpdate.isEmpty()) {
        const QRect updateRect = (expand(updateBackground) & expanded).boundingRect();
        // First we have to copy the background from the frontbuffer
        // into a scratch texture (in this case "tex").
        tex.bind();

        glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, updateRect.x(), displayHeight() - updateRect.y() - updateRect.height(),
                            updateRect.width(), updateRect.height());

        // Draw the texture on the offscreen framebuffer object, while blurring it horizontally
        target->attachTexture(targetTexture);
        GLRenderTarget::pushRenderTarget(target);

        shader->setDirection(Qt::Horizontal);
        shader->setPixelDistance(1.0 / tex.width());

        modelViewProjectionMatrix.ortho(0, r.width(), r.height(), 0 , 0, 65535);
        modelViewProjectionMatrix.translate(-r.x(), -r.y(), 0);
        shader->setModelViewProjectionMatrix(modelViewProjectionMatrix);

        // Set up the texture matrix to transform from screen coordinates
        // to texture coordinates.
        textureMatrix.scale(1.0 / tex.width(), -1.0 / tex.height(), 1);
        textureMatrix.translate(-updateRect.x(), -updateRect.height() - updateRect.y(), 0);
        shader->setTextureMatrix(textureMatrix);

        vbo->draw(GL_TRIANGLES, horizontalOffset, horizontalCount);

        GLRenderTarget::popRenderTarget();
        tex.unbind();
        // mark the updated region as valid
        it->damagedRegion -= validUpdate;
    }

    // Now draw the horizontally blurred area back to the backbuffer, while
    // blurring it vertically and clipping it to the window shape.
    targetTexture.bind();

    shader->setDirection(Qt::Vertical);
    shader->setPixelDistance(1.0 / targetTexture.height());

    // Modulate the blurred texture with the window opacity if the window isn't opaque
    if (opacity < 1.0) {
        glEnable(GL_BLEND);
        glBlendColor(0, 0, 0, opacity);
        glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA);
    }

    modelViewProjectionMatrix.setToIdentity();
    const QSize screenSize = effects->virtualScreenSize();
    modelViewProjectionMatrix.ortho(0, screenSize.width(), screenSize.height(), 0, 0, 65535);
    shader->setModelViewProjectionMatrix(modelViewProjectionMatrix);

    // Set the up the texture matrix to transform from screen coordinates
    // to texture coordinates.
    textureMatrix.setToIdentity();
    textureMatrix.scale(1.0 / targetTexture.width(), -1.0 / targetTexture.height(), 1);
    textureMatrix.translate(-r.x(), -targetTexture.height() - r.y(), 0);
    shader->setTextureMatrix(textureMatrix);

    vbo->draw(GL_TRIANGLES, verticalOffset, verticalCount);
    vbo->unbindArrays();

    if (opacity < 1.0) {
        glDisable(GL_BLEND);
    }

    targetTexture.unbind();
    shader->unbind();
}
Exemplo n.º 23
0
void BlurEffect::doBlur(const QRegion& shape, const QRect& screen, const float opacity)
{
    const QRegion expanded = expand(shape) & screen;
    const QRect r = expanded.boundingRect();

    // Upload geometry for the horizontal and vertical passes
    GLVertexBuffer *vbo = GLVertexBuffer::streamingBuffer();
    uploadGeometry(vbo, expanded, shape);
    vbo->bindArrays();

    // Create a scratch texture and copy the area in the back buffer that we're
    // going to blur into it
    GLTexture scratch(r.width(), r.height());
    scratch.setFilter(GL_LINEAR);
    scratch.setWrapMode(GL_CLAMP_TO_EDGE);
    scratch.bind();

    glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r.x(), displayHeight() - r.y() - r.height(),
                        r.width(), r.height());

    // Draw the texture on the offscreen framebuffer object, while blurring it horizontally
    target->attachTexture(tex);
    GLRenderTarget::pushRenderTarget(target);

    shader->bind();
    shader->setDirection(Qt::Horizontal);
    shader->setPixelDistance(1.0 / r.width());

    // Set up the texture matrix to transform from screen coordinates
    // to texture coordinates.
    QMatrix4x4 textureMatrix;
    textureMatrix.scale(1.0 / scratch.width(), -1.0 / scratch.height(), 1);
    textureMatrix.translate(-r.x(), -scratch.height() - r.y(), 0);
    shader->setTextureMatrix(textureMatrix);

    vbo->draw(GL_TRIANGLES, 0, expanded.rectCount() * 6);

    GLRenderTarget::popRenderTarget();
    scratch.unbind();
    scratch.discard();

    // Now draw the horizontally blurred area back to the backbuffer, while
    // blurring it vertically and clipping it to the window shape.
    tex.bind();

    shader->setDirection(Qt::Vertical);
    shader->setPixelDistance(1.0 / tex.height());

    // Modulate the blurred texture with the window opacity if the window isn't opaque
    if (opacity < 1.0) {
        glEnable(GL_BLEND);
        glBlendColor(0, 0, 0, opacity);
        glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA);
    }

    // Set the up the texture matrix to transform from screen coordinates
    // to texture coordinates.
    textureMatrix.setToIdentity();
    textureMatrix.scale(1.0 / tex.width(), -1.0 / tex.height(), 1);
    textureMatrix.translate(0, -tex.height(), 0);
    shader->setTextureMatrix(textureMatrix);

    vbo->draw(GL_TRIANGLES, expanded.rectCount() * 6, shape.rectCount() * 6);
    vbo->unbindArrays();

    if (opacity < 1.0) {
        glDisable(GL_BLEND);
    }

    tex.unbind();
    shader->unbind();
}
Exemplo n.º 24
0
void SlideEffect::desktopChanged( int old )
    {
    if( effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this )
        return;
    
    if( slide ) // old slide still in progress
        {
        QPoint diffPos = desktopRect( old ).topLeft() - slide_start_pos;
        int w = 0;
        int h = 0;
        if( effects->optionRollOverDesktops())
            {
            w = effects->workspaceWidth();
            h = effects->workspaceHeight();
            // wrap around if shorter
            if( diffPos.x() > 0 && diffPos.x() > w / 2 )
                diffPos.setX( diffPos.x() - w );
            if( diffPos.x() < 0 && abs( diffPos.x()) > w / 2 )
                diffPos.setX( diffPos.x() + w );
            if( diffPos.y() > 0 && diffPos.y() > h / 2 )
                diffPos.setY( diffPos.y() - h );
            if( diffPos.y() < 0 && abs( diffPos.y()) > h / 2 )
                diffPos.setY( diffPos.y() + h );
            }
        QPoint currentPos = slide_start_pos + mTimeLine.value() * diffPos;
        QRegion currentRegion = QRect( currentPos, QSize( displayWidth(), displayHeight()));
        if( effects->optionRollOverDesktops())
            {
            currentRegion |= ( currentRegion & QRect( -w, 0, w, h )).translated( w, 0 );
            currentRegion |= ( currentRegion & QRect( 0, -h, w, h )).translated( 0, h );
            currentRegion |= ( currentRegion & QRect( w, 0, w, h )).translated( -w, 0 );
            currentRegion |= ( currentRegion & QRect( 0, h, w, h )).translated( 0, -h );
            }
        QRect rect = desktopRect( effects->currentDesktop() );
        if( currentRegion.contains( rect ))
            { // current position is in new current desktop (e.g. quickly changing back),
              // don't do full progress
            if( abs( currentPos.x() - rect.x()) > abs( currentPos.y() - rect.y()))
                mTimeLine.setProgress(1 - abs( currentPos.x() - rect.x()) / double( displayWidth()));
            else
                mTimeLine.setProgress(1 - abs( currentPos.y() - rect.y()) / double( displayHeight()));
            }
        else // current position is not on current desktop, do full progress
            mTimeLine.setProgress(0);
        diffPos = rect.topLeft() - currentPos;
        if( mTimeLine.value() <= 0 )
            {
            // Compute starting point for this new move (given current and end positions)
            slide_start_pos = rect.topLeft() - diffPos * 1 / ( 1 - mTimeLine.value() );
            }
        else
            { // at the end, stop
            slide = false;
            mTimeLine.setProgress(0);
            effects->setActiveFullScreenEffect( NULL );
            }
        }
    else
        {
        if( effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this )
            return;
        mTimeLine.setProgress(0);
        slide_start_pos = desktopRect( old ).topLeft();
        slide = true;
        effects->setActiveFullScreenEffect( this );
        }
    effects->addRepaintFull();
    }
Exemplo n.º 25
0
void SlideEffect::paintScreen( int mask, QRegion region, ScreenPaintData& data )
    {
    if( mTimeLine.value() == 0 )
        {
        effects->paintScreen( mask, region, data );
        return;
        }
    
    /*
     Transformations are done by remembering starting position of the change and the progress
     of it, the destination is computed from the current desktop. Positions of desktops
     are done using their topleft corner.
    */
    QPoint destPos = desktopRect( effects->currentDesktop() ).topLeft();
    QPoint diffPos = destPos - slide_start_pos;
    int w = 0;
    int h = 0;
    if( effects->optionRollOverDesktops())
        {
        w = effects->workspaceWidth();
        h = effects->workspaceHeight();
        // wrap around if shorter
        if( diffPos.x() > 0 && diffPos.x() > w / 2 )
            diffPos.setX( diffPos.x() - w );
        if( diffPos.x() < 0 && abs( diffPos.x()) > w / 2 )
            diffPos.setX( diffPos.x() + w );
        if( diffPos.y() > 0 && diffPos.y() > h / 2 )
            diffPos.setY( diffPos.y() - h );
        if( diffPos.y() < 0 && abs( diffPos.y()) > h / 2 )
            diffPos.setY( diffPos.y() + h );
        }
    QPoint currentPos = slide_start_pos + mTimeLine.value() * diffPos;
    QSize displaySize( displayWidth(), displayHeight());
    QRegion currentRegion = QRect( currentPos, displaySize );
    if( effects->optionRollOverDesktops())
        {
        currentRegion |= ( currentRegion & QRect( -w, 0, w, h )).translated( w, 0 );
        currentRegion |= ( currentRegion & QRect( 0, -h, w, h )).translated( 0, h );
        currentRegion |= ( currentRegion & QRect( w, 0, w, h )).translated( -w, 0 );
        currentRegion |= ( currentRegion & QRect( 0, h, w, h )).translated( 0, -h );
        }
    bool do_sticky = true;
    for( int desktop = 1;
         desktop <= effects->numberOfDesktops();
         ++desktop )
        {
        QRect rect = desktopRect( desktop );
        if( currentRegion.contains( rect )) // part of the desktop needs painting
            {
            painting_desktop = desktop;
            slide_painting_sticky = do_sticky;
            slide_painting_diff = rect.topLeft() - currentPos;
            if( effects->optionRollOverDesktops())
                {
                if( slide_painting_diff.x() > displayWidth())
                    slide_painting_diff.setX( slide_painting_diff.x() - w );
                if( slide_painting_diff.x() < -displayWidth())
                    slide_painting_diff.setX( slide_painting_diff.x() + w );
                if( slide_painting_diff.y() > displayHeight())
                    slide_painting_diff.setY( slide_painting_diff.y() - h );
                if( slide_painting_diff.y() < -displayHeight())
                    slide_painting_diff.setY( slide_painting_diff.y() + h );
                }
            do_sticky = false; // paint on-all-desktop windows only once
            ScreenPaintData d = data;
            d.xTranslate += slide_painting_diff.x();
            d.yTranslate += slide_painting_diff.y();
            // TODO mask parts that are not visible?
            effects->paintScreen( mask, region, d );
            }
        }
    }
Exemplo n.º 26
0
void X11XRenderBackend::createBuffer()
{
    xcb_pixmap_t pixmap = xcb_generate_id(connection());
    xcb_create_pixmap(connection(), Xcb::defaultDepth(), pixmap, rootWindow(), displayWidth(), displayHeight());
    xcb_render_picture_t b = xcb_generate_id(connection());
    xcb_render_create_picture(connection(), b, pixmap, m_format, 0, NULL);
    xcb_free_pixmap(connection(), pixmap);   // The picture owns the pixmap now
    setBuffer(b);
}
Exemplo n.º 27
0
void SceneOpenGL::setupModelViewProjectionMatrix()
{
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    float fovy = 60.0f;
    float aspect = 1.0f;
    float zNear = 0.1f;
    float zFar = 100.0f;
    float ymax = zNear * tan(fovy  * M_PI / 360.0f);
    float ymin = -ymax;
    float xmin =  ymin * aspect;
    float xmax = ymax * aspect;
    // swap top and bottom to have OpenGL coordinate system match X system
    glFrustum(xmin, xmax, ymin, ymax, zNear, zFar);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    float scaleFactor = 1.1 * tan(fovy * M_PI / 360.0f) / ymax;
    glTranslatef(xmin * scaleFactor, ymax * scaleFactor, -1.1);
    glScalef((xmax - xmin)*scaleFactor / displayWidth(), -(ymax - ymin)*scaleFactor / displayHeight(), 0.001);
    m_resetModelViewProjectionMatrix = false;
}