[software development] 使用dde-kwin的时候有发现它这里解绑怪怪的吗
Tofloor
poster avatar
159******15
deepin
2025-04-28 16:52
Author

绑定的是纹理块2,解绑的时候确在纹理块0执行,有没有大佬告诉我为什么
image.png

Reply Favorite View the author
All Replies
zccrs
deepin
2025-04-29 09:45
#1
#if KWIN_VERSION_MIN > 17 || (KWIN_VERSION_MIN == 17 && KWIN_VERSION_PAT > 5)
void ScissorWindow::drawWindow(KWin::EffectWindow *w, int mask, const QRegion &_region, KWin::WindowPaintData &data)
{
    QRegion region = _region;
#else
void ScissorWindow::drawWindow(KWin::EffectWindow *w, int mask, QRegion region, KWin::WindowPaintData &data)
{
#endif
    // 工作区特效会使用PAINT_WINDOW_LANCZOS绘制,此时不支持多次调用Effect::drawWindow,
    // 否则只会显示第一次调用绘制的内容, 因此在这种模式下禁用掉窗口裁剪特效
    if (!w->isPaintingEnabled() || (mask & PAINT_WINDOW_LANCZOS) || w->isDesktop()) {
        return Effect::drawWindow(w, mask, region, data);
    }

    MaskCache::TextureData mask_texture = MaskCache::instance()->getTextureByWindow(w);

    if (!mask_texture) {
        return Effect::drawWindow(w, mask, region, data);
    }

    QRegion corner_region;

    if (!mask_texture->customMask) {
        const QRect window_rect = w->geometry();
        QRect corner_rect(window_rect.topLeft(), mask_texture->size);

        // top left
        corner_region += corner_rect;
        // top right
        corner_rect.moveRight(window_rect.right());
        corner_region += corner_rect;
        // bottom right
        corner_rect.moveBottom(window_rect.bottom());
        corner_region += corner_rect;
        // bottom left
        corner_rect.moveLeft(window_rect.left());
        corner_region += corner_rect;

        // 本次绘制未包含圆角区域时则直接按原有的行为渲染
        if ((region & corner_region).isEmpty()) {
            return Effect::drawWindow(w, mask, region, data);
        }

        // 窗口发生几何转换时不能拆分绘制窗口的区域,否则会导致两个区域不契合,例如开启wobbly windows窗口特效,
        // 移动窗口时会导致窗口圆角出现毛刺
        if (mask & PAINT_WINDOW_TRANSFORMED) {
            corner_region = QRegion();
        }
    }

    KWin::WindowQuadList decoration_quad_list;
    KWin::WindowQuadList content_quad_list;

    for (const KWin::WindowQuad &quad : data.quads) {
        switch (quad.type()) {
        case KWin::WindowQuadShadow:
        case KWin::WindowQuadDecoration:
            decoration_quad_list.append(quad);
            break;
        case KWin::WindowQuadContents:
            content_quad_list.append(quad);
            break;
        default:
            break;
        }
    }

    if (!mask_texture->customMask) {
        // 此时只允许绘制窗口边框和阴影
        // 针对设置了自定义裁剪的窗口,则不绘制标题栏和阴影
        data.quads = decoration_quad_list;

        if (KWin::effects->waylandDisplay()) {
            if (!w->isDock()) {
                Effect::drawWindow(w, mask, region, data);
            }
        } else {
            Effect::drawWindow(w, mask, region, data);
        }
    }

    if (!corner_region.isEmpty()) {
        QRegion new_region = region - corner_region;

        // 先绘制未处于mask区域的窗口材质
        if (!new_region.isEmpty()) {
            data.quads = content_quad_list;
            Effect::drawWindow(w, mask, new_region, data);
        }

        // 重新设置要绘制的区域
        region = region - new_region;
    }

    // 将mask材质绑定到第二个材质
    glActiveTexture(GL_TEXTURE1);
    mask_texture->bind();

    // 对于窗口圆角的材质,由于其需要被访问材质范围外的像素,在此设置范围外材质的颜色
    // 其中alpha通道为1表示此处的窗口像素完全显示
    if (!mask_texture->customMask) {
        float borderColor[] = { 1.0f, 1.0f, 1.0f, 1.0f };
        glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
    }

    // 重新激活第一个材质
    glActiveTexture(GL_TEXTURE0);

    // 激活着色器
    KWin::GLShader *shader = mask_texture->customMask ? m_fullMaskShader : m_shader;
    KWin::ShaderManager::instance()->pushShader(shader);
    shader->setUniform("mask", 1);

    if (!mask_texture->customMask) {
        shader->setUniform("scale", QVector2D(w->width() / qreal(mask_texture->size.width()), w->height() / qreal(mask_texture->size.height())));
    }

    // 此时只允许绘制窗口内容
    auto old_shader = data.shader;
    data.quads = content_quad_list;
    data.shader = shader;

#ifndef DISBLE_DDE_KWIN_XCB
    class SetWindowDepth {
    public:
        SetWindowDepth(KWin::EffectWindow *w, int depth)
            : m_window(w)
        {
            // 此时正在进行窗口绘制,会有大量的调用,应当避免窗口发射hasAlphaChanged信号
            QSignalBlocker blocker(w->parent());
            Q_UNUSED(blocker)
            KWinUtils::setClientDepth(w->parent(), depth);
        }

        ~SetWindowDepth() {
            bool ok = false;
            int depth = m_window->data(WindowDepthRole).toInt(&ok);
            QObject *client = m_window->parent();

            if (!ok) {
                depth = KWinUtils::getWindowDepth(client);
                // 保存以便下次使用
                m_window->setData(WindowDepthRole, depth);
            }

            // 此时正在进行窗口绘制,会有大量的调用,应当避免窗口发射hasAlphaChanged信号
            QSignalBlocker blocker(client);
            Q_UNUSED(blocker)
            KWinUtils::setClientDepth(client, depth);
        }

    private:
        KWin::EffectWindow *m_window;
    };

    // 要想窗口裁剪生效,必须要保证窗口材质绘制时开启了alpha通道混合
    if (!w->hasAlpha()) {
        SetWindowDepth set_depth(w, 32);
        Q_UNUSED(set_depth)
        Effect::drawWindow(w, mask, region, data);
    } else
#endif
    {
        Effect::drawWindow(w, mask, region, data);
    }

    data.shader = old_shader;

    KWin::ShaderManager::instance()->popShader();
    // 解除材质绑定
    glActiveTexture(GL_TEXTURE1);
    mask_texture->unbind();
    glActiveTexture(GL_TEXTURE0);
}

你看的哪个版本?

Reply View the author
zccrs
deepin
2025-04-29 09:47
#2

建议看 https://github.com/linuxdeepin/dde-kwin/tree/maintain/v20sp1 这个分支上最原始的版本,不一定能编译过,但是实现逻辑是可参考的。

Reply View the author