File indexing completed on 2024-11-10 04:56:34

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2008 Lubos Lunak <l.lunak@kde.org>
0006     SPDX-FileCopyrightText: 2022 MBition GmbH
0007     SPDX-FileContributor: Kai Uwe Broulik <kai_uwe.broulik@mbition.io>
0008 
0009     SPDX-License-Identifier: GPL-2.0-or-later
0010 */
0011 
0012 #include "kwinxrenderutils.h"
0013 #include "x11_common_logging_p.h"
0014 
0015 #include <QCoreApplication>
0016 #include <QImage>
0017 
0018 namespace KWin
0019 {
0020 
0021 namespace XRenderUtils
0022 {
0023 static xcb_connection_t *s_connection = nullptr;
0024 static xcb_window_t s_rootWindow = XCB_WINDOW_NONE;
0025 
0026 void init(xcb_connection_t *connection, xcb_window_t rootWindow)
0027 {
0028     s_connection = connection;
0029     s_rootWindow = rootWindow;
0030 }
0031 
0032 void cleanup()
0033 {
0034     s_connection = nullptr;
0035     s_rootWindow = XCB_WINDOW_NONE;
0036 }
0037 
0038 } // namespace
0039 
0040 static xcb_render_picture_t createPicture(xcb_pixmap_t pix, int depth)
0041 {
0042     if (pix == XCB_PIXMAP_NONE) {
0043         return XCB_RENDER_PICTURE_NONE;
0044     }
0045     xcb_connection_t *c = XRenderUtils::s_connection;
0046     static QHash<int, xcb_render_pictformat_t> s_renderFormats;
0047     if (!s_renderFormats.contains(depth)) {
0048         xcb_render_query_pict_formats_reply_t *formats = xcb_render_query_pict_formats_reply(c, xcb_render_query_pict_formats_unchecked(c), nullptr);
0049         if (!formats) {
0050             return XCB_RENDER_PICTURE_NONE;
0051         }
0052         for (xcb_render_pictforminfo_iterator_t it = xcb_render_query_pict_formats_formats_iterator(formats);
0053              it.rem;
0054              xcb_render_pictforminfo_next(&it)) {
0055             if (it.data->depth == depth) {
0056                 s_renderFormats.insert(depth, it.data->id);
0057                 break;
0058             }
0059         }
0060         free(formats);
0061     }
0062     QHash<int, xcb_render_pictformat_t>::const_iterator it = s_renderFormats.constFind(depth);
0063     if (it == s_renderFormats.constEnd()) {
0064         qCWarning(LIBKWINXRENDERUTILS) << "Could not find XRender format for depth" << depth;
0065         return XCB_RENDER_PICTURE_NONE;
0066     }
0067     xcb_render_picture_t pic = xcb_generate_id(c);
0068     xcb_render_create_picture(c, pic, pix, it.value(), 0, nullptr);
0069     return pic;
0070 }
0071 
0072 XRenderPicture::XRenderPicture(const QImage &img)
0073 {
0074     fromImage(img);
0075 }
0076 
0077 void XRenderPicture::fromImage(const QImage &img)
0078 {
0079     xcb_connection_t *c = XRenderUtils::s_connection;
0080     const int depth = img.depth();
0081     xcb_pixmap_t xpix = xcb_generate_id(c);
0082     xcb_create_pixmap(c, depth, xpix, XRenderUtils::s_rootWindow, img.width(), img.height());
0083 
0084     xcb_gcontext_t cid = xcb_generate_id(c);
0085     xcb_create_gc(c, cid, xpix, 0, nullptr);
0086     xcb_put_image(c, XCB_IMAGE_FORMAT_Z_PIXMAP, xpix, cid, img.width(), img.height(),
0087                   0, 0, 0, depth, img.sizeInBytes(), img.constBits());
0088     xcb_free_gc(c, cid);
0089 
0090     d = std::make_unique<XRenderPictureData>(createPicture(xpix, depth));
0091     xcb_free_pixmap(c, xpix);
0092 }
0093 
0094 XRenderPicture::XRenderPicture(xcb_pixmap_t pix, int depth)
0095     : d(std::make_unique<XRenderPictureData>(createPicture(pix, depth)))
0096 {
0097 }
0098 
0099 XRenderPictureData::~XRenderPictureData()
0100 {
0101     if (picture != XCB_RENDER_PICTURE_NONE) {
0102         Q_ASSERT(qApp);
0103         xcb_render_free_picture(XRenderUtils::s_connection, picture);
0104     }
0105 }
0106 
0107 namespace XRenderUtils
0108 {
0109 
0110 struct PictFormatData
0111 {
0112     PictFormatData()
0113     {
0114         // Fetch the render pict formats
0115         reply = xcb_render_query_pict_formats_reply(s_connection,
0116                                                     xcb_render_query_pict_formats_unchecked(s_connection), nullptr);
0117 
0118         // Init the visual ID -> format ID hash table
0119         for (auto screens = xcb_render_query_pict_formats_screens_iterator(reply); screens.rem; xcb_render_pictscreen_next(&screens)) {
0120             for (auto depths = xcb_render_pictscreen_depths_iterator(screens.data); depths.rem; xcb_render_pictdepth_next(&depths)) {
0121                 const xcb_render_pictvisual_t *visuals = xcb_render_pictdepth_visuals(depths.data);
0122                 const int len = xcb_render_pictdepth_visuals_length(depths.data);
0123 
0124                 for (int i = 0; i < len; i++) {
0125                     visualHash.insert(visuals[i].visual, visuals[i].format);
0126                 }
0127             }
0128         }
0129 
0130         // Init the format ID -> xcb_render_directformat_t* hash table
0131         const xcb_render_pictforminfo_t *formats = xcb_render_query_pict_formats_formats(reply);
0132         const int len = xcb_render_query_pict_formats_formats_length(reply);
0133 
0134         for (int i = 0; i < len; i++) {
0135             if (formats[i].type == XCB_RENDER_PICT_TYPE_DIRECT) {
0136                 formatInfoHash.insert(formats[i].id, &formats[i].direct);
0137             }
0138         }
0139     }
0140 
0141     ~PictFormatData()
0142     {
0143         free(reply);
0144     }
0145 
0146     xcb_render_query_pict_formats_reply_t *reply;
0147     QHash<xcb_visualid_t, xcb_render_pictformat_t> visualHash;
0148     QHash<xcb_render_pictformat_t, const xcb_render_directformat_t *> formatInfoHash;
0149 };
0150 
0151 Q_GLOBAL_STATIC(PictFormatData, g_pictFormatData)
0152 
0153 xcb_render_pictformat_t findPictFormat(xcb_visualid_t visual)
0154 {
0155     PictFormatData *d = g_pictFormatData;
0156     return d->visualHash.value(visual);
0157 }
0158 
0159 const xcb_render_directformat_t *findPictFormatInfo(xcb_render_pictformat_t format)
0160 {
0161     PictFormatData *d = g_pictFormatData;
0162     return d->formatInfoHash.value(format);
0163 }
0164 
0165 } // namespace XRenderUtils
0166 
0167 } // namespace KWin