kwin: implement option to set the X11 picture filter to any of the currently supported, default to "good"

obviously using the "good" filter as default can have a performance impact
but if the system cannot handle it the option is there

Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
Ivailo Monev 2023-10-22 17:53:08 +03:00
parent ba3c114047
commit f9f7c94639
9 changed files with 111 additions and 58 deletions

View file

@ -155,7 +155,6 @@ void MagnifierEffect::paintScreen(int mask, QRegion region, ScreenPaintData& dat
xcb_render_set_picture_filter(connection(), *m_picture, 4, const_cast<char*>("good"), 0, NULL); xcb_render_set_picture_filter(connection(), *m_picture, 4, const_cast<char*>("good"), 0, NULL);
xcb_render_composite(connection(), XCB_RENDER_PICT_OP_SRC, *m_picture, 0, effects->xrenderBufferPicture(), xcb_render_composite(connection(), XCB_RENDER_PICT_OP_SRC, *m_picture, 0, effects->xrenderBufferPicture(),
0, 0, 0, 0, area.x(), area.y(), area.width(), area.height() ); 0, 0, 0, 0, area.x(), area.y(), area.width(), area.height() );
xcb_render_set_picture_filter(connection(), *m_picture, 4, const_cast<char*>("fast"), 0, NULL);
xcb_render_set_picture_transform(connection(), *m_picture, identity); xcb_render_set_picture_transform(connection(), *m_picture, identity);
const xcb_rectangle_t rects[4] = { const xcb_rectangle_t rects[4] = {
{ int16_t(area.x()+FRAME_WIDTH), int16_t(area.y()), uint16_t(area.width()-FRAME_WIDTH), uint16_t(FRAME_WIDTH)}, { int16_t(area.x()+FRAME_WIDTH), int16_t(area.y()), uint16_t(area.width()-FRAME_WIDTH), uint16_t(FRAME_WIDTH)},

View file

@ -50,6 +50,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <KPluginLoader> #include <KPluginLoader>
#include <KIcon> #include <KIcon>
static int s_xrenderfilter = 1; // KWin::Scene::ImageFilterGood
K_PLUGIN_FACTORY(KWinCompositingConfigFactory, K_PLUGIN_FACTORY(KWinCompositingConfigFactory,
registerPlugin<KWin::KWinCompositingConfig>(); registerPlugin<KWin::KWinCompositingConfig>();
) )
@ -58,7 +60,6 @@ K_EXPORT_PLUGIN(KWinCompositingConfigFactory("kcmkwincompositing"))
namespace KWin namespace KWin
{ {
ConfirmDialog::ConfirmDialog() : ConfirmDialog::ConfirmDialog() :
KTimerDialog(10000, KTimerDialog::CountDown, 0, KTimerDialog(10000, KTimerDialog::CountDown, 0,
i18n("Confirm Desktop Effects Change"), KTimerDialog::Ok | KTimerDialog::Cancel, i18n("Confirm Desktop Effects Change"), KTimerDialog::Ok | KTimerDialog::Cancel,
@ -364,7 +365,7 @@ void KWinCompositingConfig::loadAdvancedTab()
ui.windowThumbnails->setCurrentIndex(1); ui.windowThumbnails->setCurrentIndex(1);
ui.unredirectFullscreen->setChecked(config.readEntry("UnredirectFullscreen", false)); ui.unredirectFullscreen->setChecked(config.readEntry("UnredirectFullscreen", false));
ui.xrScaleFilter->setCurrentIndex((int)config.readEntry("XRenderSmoothScale", false)); ui.xrScaleFilter->setCurrentIndex(config.readEntry("XRenderFilter", s_xrenderfilter));
alignGuiToCompositingType(ui.compositingType->currentIndex()); alignGuiToCompositingType(ui.compositingType->currentIndex());
} }
@ -464,7 +465,7 @@ bool KWinCompositingConfig::saveAdvancedTab()
} }
if (config.readEntry("HiddenPreviews", 5) != hps[ ui.windowThumbnails->currentIndex()] if (config.readEntry("HiddenPreviews", 5) != hps[ ui.windowThumbnails->currentIndex()]
|| (int)config.readEntry("XRenderSmoothScale", false) != ui.xrScaleFilter->currentIndex() || config.readEntry("XRenderFilter", s_xrenderfilter) != ui.xrScaleFilter->currentIndex()
|| config.readEntry("Backend") != ui.compositingType->currentText()) { || config.readEntry("Backend") != ui.compositingType->currentText()) {
advancedChanged = true; advancedChanged = true;
} }
@ -474,7 +475,7 @@ bool KWinCompositingConfig::saveAdvancedTab()
config.writeEntry("HiddenPreviews", hps[ ui.windowThumbnails->currentIndex()]); config.writeEntry("HiddenPreviews", hps[ ui.windowThumbnails->currentIndex()]);
config.writeEntry("UnredirectFullscreen", ui.unredirectFullscreen->isChecked()); config.writeEntry("UnredirectFullscreen", ui.unredirectFullscreen->isChecked());
config.writeEntry("XRenderSmoothScale", ui.xrScaleFilter->currentIndex() == 1); config.writeEntry("XRenderFilter", ui.xrScaleFilter->currentIndex());
return advancedChanged; return advancedChanged;
} }
@ -692,7 +693,7 @@ void KWinCompositingConfig::defaults()
ui.compositingType->setCurrentIndex(XRENDER_INDEX); ui.compositingType->setCurrentIndex(XRENDER_INDEX);
ui.windowThumbnails->setCurrentIndex(1); ui.windowThumbnails->setCurrentIndex(1);
ui.unredirectFullscreen->setChecked(false); ui.unredirectFullscreen->setChecked(false);
ui.xrScaleFilter->setCurrentIndex(0); ui.xrScaleFilter->setCurrentIndex(s_xrenderfilter);
} }
QString KWinCompositingConfig::quickHelp() const QString KWinCompositingConfig::quickHelp() const

View file

@ -547,28 +547,68 @@
<item> <item>
<widget class="QComboBox" name="xrScaleFilter"> <widget class="QComboBox" name="xrScaleFilter">
<property name="toolTip"> <property name="toolTip">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt; <string>
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt; &lt;b&gt;Fast:&lt;/b&gt;&lt;br/&gt;
p, li { white-space: pre-wrap; } &lt;i&gt;XRenderSetPictureFilter(&quot;fast&quot;)&lt;/i&gt; - pretty fast on all GPUs but looks bricky
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Segoe'; font-size:8pt; font-weight:400; font-style:normal;&quot;&gt; &lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Crisp:&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;XRenderSetPictureFilter(&amp;quot;fast&amp;quot;)&lt;/span&gt; - Pretty fast on all GPUs but looks bricky&lt;/p&gt; &lt;p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt; &lt;b&gt;Good:&lt;/b&gt;&lt;br/&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Smooth:&lt;/span&gt;&lt;/p&gt; &lt;i&gt;XRenderSetPictureFilter(&quot;good&quot;)&lt;/i&gt; - linear blending, fast enough on newer GPUs and maybe others but also can be slow (default)
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;XRenderSetPictureFilter(&amp;quot;good&amp;quot;) &lt;/span&gt;- linear blending.&lt;/p&gt; &lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Fast enough on newer nvidia GPUs and maybe others but also can be &lt;span style=&quot; text-decoration: underline;&quot;&gt;very&lt;/span&gt; slow, you will have to try it.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
&lt;p&gt;
&lt;b&gt;Best:&lt;/b&gt;&lt;br/&gt;
&lt;i&gt;XRenderSetPictureFilter(&quot;best&quot;)&lt;/i&gt; - best filter there is, can be &lt;u&gt;very&lt;/u&gt; slow
&lt;/p&gt;
&lt;p&gt;
&lt;b&gt;Nearest:&lt;/b&gt;&lt;br/&gt;
&lt;i&gt;XRenderSetPictureFilter(&quot;nearest&quot;)&lt;/i&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;b&gt;Bilinear:&lt;/b&gt;&lt;br/&gt;
&lt;i&gt;XRenderSetPictureFilter(&quot;bilinear&quot;)&lt;/i&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;b&gt;Convolution:&lt;/b&gt;&lt;br/&gt;
&lt;i&gt;XRenderSetPictureFilter(&quot;convolution&quot;)&lt;/i&gt;
&lt;/p&gt;
</string>
</property> </property>
<property name="currentIndex"> <property name="currentIndex">
<number>0</number> <number>1</number>
</property> </property>
<item> <item>
<property name="text"> <property name="text">
<string>Crisp</string> <string>Fast</string>
</property> </property>
</item> </item>
<item> <item>
<property name="text"> <property name="text">
<string>Smooth (slower)</string> <string>Good</string>
</property>
</item>
<item>
<property name="text">
<string>Best</string>
</property>
</item>
<item>
<property name="text">
<string>Nearest</string>
</property>
</item>
<item>
<property name="text">
<string>Bilinear</string>
</property>
</item>
<item>
<property name="text">
<string>Convolution</string>
</property> </property>
</item> </item>
</widget> </widget>

View file

@ -235,8 +235,8 @@
<entry name="Enabled" type="Bool"> <entry name="Enabled" type="Bool">
<default>true</default> <default>true</default>
</entry> </entry>
<entry name="XRenderSmoothScale" type="Bool"> <entry name="XRenderFilter" type="UInt">
<default>false</default> <default>1</default>
</entry> </entry>
<entry name="HiddenPreviews" type="Int"> <entry name="HiddenPreviews" type="Int">
<default>5</default> <default>5</default>

View file

@ -99,7 +99,7 @@ Options::Options(QObject *parent)
, m_compositingInitialized(Options::defaultCompositingInitialized()) , m_compositingInitialized(Options::defaultCompositingInitialized())
, m_hiddenPreviews(Options::defaultHiddenPreviews()) , m_hiddenPreviews(Options::defaultHiddenPreviews())
, m_unredirectFullscreen(Options::defaultUnredirectFullscreen()) , m_unredirectFullscreen(Options::defaultUnredirectFullscreen())
, m_xrenderSmoothScale(Options::defaultXrenderSmoothScale()) , m_xrenderFilter(Options::defaultXrenderFilter())
, m_maxFpsInterval(Options::defaultMaxFpsInterval()) , m_maxFpsInterval(Options::defaultMaxFpsInterval())
, m_refreshRate(Options::defaultRefreshRate()) , m_refreshRate(Options::defaultRefreshRate())
, m_vBlankTime(Options::defaultVBlankTime()) , m_vBlankTime(Options::defaultVBlankTime())
@ -602,13 +602,13 @@ void Options::setUnredirectFullscreen(bool unredirectFullscreen)
emit unredirectFullscreenChanged(); emit unredirectFullscreenChanged();
} }
void Options::setXrenderSmoothScale(bool xrenderSmoothScale) void Options::setXrenderFilter(uint xrenderFilter)
{ {
if (m_xrenderSmoothScale == xrenderSmoothScale) { if (m_xrenderFilter == xrenderFilter) {
return; return;
} }
m_xrenderSmoothScale = xrenderSmoothScale; m_xrenderFilter = xrenderFilter;
emit xrenderSmoothScaleChanged(); emit xrenderFilterChanged();
} }
void Options::setMaxFpsInterval(qint64 maxFpsInterval) void Options::setMaxFpsInterval(qint64 maxFpsInterval)
@ -792,7 +792,7 @@ void Options::reloadCompositingSettings(bool force)
KSharedConfig::Ptr _config = KGlobal::config(); KSharedConfig::Ptr _config = KGlobal::config();
KConfigGroup config(_config, "Compositing"); KConfigGroup config(_config, "Compositing");
m_xrenderSmoothScale = config.readEntry("XRenderSmoothScale", false); m_xrenderFilter = config.readEntry("XRenderFilter", 1);
HiddenPreviews previews = Options::defaultHiddenPreviews(); HiddenPreviews previews = Options::defaultHiddenPreviews();
// 4 - off, 5 - shown, 6 - always, other are old values // 4 - off, 5 - shown, 6 - always, other are old values

View file

@ -162,7 +162,7 @@ class Options : public QObject, public KDecorationOptions
* 2 = try trilinear when transformed; else 1, * 2 = try trilinear when transformed; else 1,
* -1 = auto * -1 = auto
**/ **/
Q_PROPERTY(bool xrenderSmoothScale READ isXrenderSmoothScale WRITE setXrenderSmoothScale NOTIFY xrenderSmoothScaleChanged) Q_PROPERTY(uint xrenderFilter READ xrenderFilter WRITE setXrenderFilter NOTIFY xrenderFilterChanged)
Q_PROPERTY(qint64 maxFpsInterval READ maxFpsInterval WRITE setMaxFpsInterval NOTIFY maxFpsIntervalChanged) Q_PROPERTY(qint64 maxFpsInterval READ maxFpsInterval WRITE setMaxFpsInterval NOTIFY maxFpsIntervalChanged)
Q_PROPERTY(uint refreshRate READ refreshRate WRITE setRefreshRate NOTIFY refreshRateChanged) Q_PROPERTY(uint refreshRate READ refreshRate WRITE setRefreshRate NOTIFY refreshRateChanged)
Q_PROPERTY(qint64 vBlankTime READ vBlankTime WRITE setVBlankTime NOTIFY vBlankTimeChanged) Q_PROPERTY(qint64 vBlankTime READ vBlankTime WRITE setVBlankTime NOTIFY vBlankTimeChanged)
@ -484,8 +484,8 @@ public:
return m_unredirectFullscreen; return m_unredirectFullscreen;
} }
// XRender // XRender
bool isXrenderSmoothScale() const { uint xrenderFilter() const {
return m_xrenderSmoothScale; return m_xrenderFilter;
} }
qint64 maxFpsInterval() const { qint64 maxFpsInterval() const {
@ -549,7 +549,7 @@ public:
void setCompositingInitialized(bool compositingInitialized); void setCompositingInitialized(bool compositingInitialized);
void setHiddenPreviews(int hiddenPreviews); void setHiddenPreviews(int hiddenPreviews);
void setUnredirectFullscreen(bool unredirectFullscreen); void setUnredirectFullscreen(bool unredirectFullscreen);
void setXrenderSmoothScale(bool xrenderSmoothScale); void setXrenderFilter(uint xrenderFilter);
void setMaxFpsInterval(qint64 maxFpsInterval); void setMaxFpsInterval(qint64 maxFpsInterval);
void setRefreshRate(uint refreshRate); void setRefreshRate(uint refreshRate);
void setVBlankTime(qint64 vBlankTime); void setVBlankTime(qint64 vBlankTime);
@ -624,8 +624,8 @@ public:
static bool defaultUnredirectFullscreen() { static bool defaultUnredirectFullscreen() {
return false; return false;
} }
static bool defaultXrenderSmoothScale() { static uint defaultXrenderFilter() {
return false; return 1;
} }
static qint64 defaultMaxFpsInterval() { static qint64 defaultMaxFpsInterval() {
return (1 * 1000 * 1000 * 1000) /60.0; // nanoseconds / Hz return (1 * 1000 * 1000 * 1000) /60.0; // nanoseconds / Hz
@ -707,7 +707,7 @@ Q_SIGNALS:
void compositingInitializedChanged(); void compositingInitializedChanged();
void hiddenPreviewsChanged(); void hiddenPreviewsChanged();
void unredirectFullscreenChanged(); void unredirectFullscreenChanged();
void xrenderSmoothScaleChanged(); void xrenderFilterChanged();
void maxFpsIntervalChanged(); void maxFpsIntervalChanged();
void refreshRateChanged(); void refreshRateChanged();
void vBlankTimeChanged(); void vBlankTimeChanged();
@ -745,7 +745,7 @@ private:
bool m_compositingInitialized; bool m_compositingInitialized;
HiddenPreviews m_hiddenPreviews; HiddenPreviews m_hiddenPreviews;
bool m_unredirectFullscreen; bool m_unredirectFullscreen;
bool m_xrenderSmoothScale; uint m_xrenderFilter;
qint64 m_maxFpsInterval; qint64 m_maxFpsInterval;
// Settings that should be auto-detected // Settings that should be auto-detected
uint m_refreshRate; uint m_refreshRate;

View file

@ -444,7 +444,7 @@ void Scene::screenGeometryChanged(const QSize &size)
Scene::Window::Window(Toplevel * c) Scene::Window::Window(Toplevel * c)
: toplevel(c) : toplevel(c)
, filter(ImageFilterFast) , filter(ImageFilterGood)
, m_shadow(NULL) , m_shadow(NULL)
, m_currentPixmap() , m_currentPixmap()
, m_previousPixmap() , m_previousPixmap()

View file

@ -93,7 +93,14 @@ public:
PAINT_SCREEN_BACKGROUND_FIRST = 1 << 6, PAINT_SCREEN_BACKGROUND_FIRST = 1 << 6,
}; };
// types of filtering available // types of filtering available
enum ImageFilterType { ImageFilterFast, ImageFilterGood }; enum ImageFilterType {
ImageFilterFast,
ImageFilterGood,
ImageFilterBest,
ImageFilterNearest,
ImageFilterBilinear,
ImageFilterConvolution
};
// there's nothing to paint (adjust time_diff later) // there's nothing to paint (adjust time_diff later)
virtual void idle(); virtual void idle();
virtual OverlayWindow* overlayWindow() = 0; virtual OverlayWindow* overlayWindow() = 0;

View file

@ -413,16 +413,6 @@ void SceneXrender::Window::performPaint(int mask, QRegion region, WindowPaintDat
if (pic == XCB_RENDER_PICTURE_NONE) // The render format can be null for GL and/or Xv visuals if (pic == XCB_RENDER_PICTURE_NONE) // The render format can be null for GL and/or Xv visuals
return; return;
toplevel->resetDamage(); toplevel->resetDamage();
// set picture filter
if (options->isXrenderSmoothScale()) { // only when forced, it's slow
if (mask & PAINT_WINDOW_TRANSFORMED)
filter = ImageFilterGood;
else if (mask & PAINT_SCREEN_TRANSFORMED)
filter = ImageFilterGood;
else
filter = ImageFilterFast;
} else
filter = ImageFilterFast;
// do required transformations // do required transformations
const QRect wr = mapToScreen(mask, data, QRect(0, 0, width(), height())); const QRect wr = mapToScreen(mask, data, QRect(0, 0, width(), height()));
QRect cr = QRect(toplevel->clientPos(), toplevel->clientSize()); // Client rect (in the window) QRect cr = QRect(toplevel->clientPos(), toplevel->clientSize()); // Client rect (in the window)
@ -510,9 +500,7 @@ void SceneXrender::Window::performPaint(int mask, QRegion region, WindowPaintDat
} }
} else { } else {
xcb_render_set_picture_transform(connection(), pic, xform); xcb_render_set_picture_transform(connection(), pic, xform);
if (filter == ImageFilterGood) { setPictureFilter(pic, filter);
setPictureFilter(pic, KWin::Scene::ImageFilterGood);
}
//BEGIN OF STUPID RADEON HACK //BEGIN OF STUPID RADEON HACK
// This is needed to avoid hitting a fallback in the radeon driver. // This is needed to avoid hitting a fallback in the radeon driver.
@ -717,8 +705,6 @@ xcb_render_composite(connection(), XCB_RENDER_PICT_OP_OVER, _PART_, decorationAl
} }
if (scaled && !blitInTempPixmap) { if (scaled && !blitInTempPixmap) {
xcb_render_set_picture_transform(connection(), pic, identity); xcb_render_set_picture_transform(connection(), pic, identity);
if (filter == ImageFilterGood)
setPictureFilter(pic, KWin::Scene::ImageFilterFast);
if (!window()->hasAlpha()) { if (!window()->hasAlpha()) {
const uint32_t values[] = {XCB_RENDER_REPEAT_NONE}; const uint32_t values[] = {XCB_RENDER_REPEAT_NONE};
xcb_render_change_picture(connection(), pic, XCB_RENDER_CP_REPEAT, values); xcb_render_change_picture(connection(), pic, XCB_RENDER_CP_REPEAT, values);
@ -732,12 +718,32 @@ void SceneXrender::Window::setPictureFilter(xcb_render_picture_t pic, Scene::Ima
{ {
QByteArray filterName; QByteArray filterName;
switch (filter) { switch (filter) {
case KWin::Scene::ImageFilterFast: case KWin::Scene::ImageFilterFast: {
filterName = QByteArray("fast"); filterName = QByteArray("fast");
break; break;
case KWin::Scene::ImageFilterGood: }
filterName = QByteArray("good"); case KWin::Scene::ImageFilterGood: {
break; filterName = QByteArray("good");
break;
}
case KWin::Scene::ImageFilterBest: {
filterName = QByteArray("best");
break;
}
/* Filters included in 0.6 */
case KWin::Scene::ImageFilterNearest: {
filterName = QByteArray("nearest");
break;
}
case KWin::Scene::ImageFilterBilinear: {
filterName = QByteArray("bilinear");
break;
}
/* Filters included in 0.10 */
case KWin::Scene::ImageFilterConvolution: {
filterName = QByteArray("convolution");
break;
}
} }
xcb_render_set_picture_filter(connection(), pic, filterName.length(), filterName.constData(), 0, NULL); xcb_render_set_picture_filter(connection(), pic, filterName.length(), filterName.constData(), 0, NULL);
} }