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