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_composite(connection(), XCB_RENDER_PICT_OP_SRC, *m_picture, 0, effects->xrenderBufferPicture(),
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);
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)},

View file

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

View file

@ -547,28 +547,68 @@
<item>
<widget class="QComboBox" name="xrScaleFilter">
<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;
&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;
p, li { white-space: pre-wrap; }
&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 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 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;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;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 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>
<string>
&lt;b&gt;Fast:&lt;/b&gt;&lt;br/&gt;
&lt;i&gt;XRenderSetPictureFilter(&quot;fast&quot;)&lt;/i&gt; - pretty fast on all GPUs but looks bricky
&lt;/p&gt;
&lt;p&gt;
&lt;b&gt;Good:&lt;/b&gt;&lt;br/&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&gt;
&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 name="currentIndex">
<number>0</number>
<number>1</number>
</property>
<item>
<property name="text">
<string>Crisp</string>
<string>Fast</string>
</property>
</item>
<item>
<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>
</item>
</widget>

View file

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

View file

@ -99,7 +99,7 @@ Options::Options(QObject *parent)
, m_compositingInitialized(Options::defaultCompositingInitialized())
, m_hiddenPreviews(Options::defaultHiddenPreviews())
, m_unredirectFullscreen(Options::defaultUnredirectFullscreen())
, m_xrenderSmoothScale(Options::defaultXrenderSmoothScale())
, m_xrenderFilter(Options::defaultXrenderFilter())
, m_maxFpsInterval(Options::defaultMaxFpsInterval())
, m_refreshRate(Options::defaultRefreshRate())
, m_vBlankTime(Options::defaultVBlankTime())
@ -602,13 +602,13 @@ void Options::setUnredirectFullscreen(bool unredirectFullscreen)
emit unredirectFullscreenChanged();
}
void Options::setXrenderSmoothScale(bool xrenderSmoothScale)
void Options::setXrenderFilter(uint xrenderFilter)
{
if (m_xrenderSmoothScale == xrenderSmoothScale) {
if (m_xrenderFilter == xrenderFilter) {
return;
}
m_xrenderSmoothScale = xrenderSmoothScale;
emit xrenderSmoothScaleChanged();
m_xrenderFilter = xrenderFilter;
emit xrenderFilterChanged();
}
void Options::setMaxFpsInterval(qint64 maxFpsInterval)
@ -792,7 +792,7 @@ void Options::reloadCompositingSettings(bool force)
KSharedConfig::Ptr _config = KGlobal::config();
KConfigGroup config(_config, "Compositing");
m_xrenderSmoothScale = config.readEntry("XRenderSmoothScale", false);
m_xrenderFilter = config.readEntry("XRenderFilter", 1);
HiddenPreviews previews = Options::defaultHiddenPreviews();
// 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,
* -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(uint refreshRate READ refreshRate WRITE setRefreshRate NOTIFY refreshRateChanged)
Q_PROPERTY(qint64 vBlankTime READ vBlankTime WRITE setVBlankTime NOTIFY vBlankTimeChanged)
@ -484,8 +484,8 @@ public:
return m_unredirectFullscreen;
}
// XRender
bool isXrenderSmoothScale() const {
return m_xrenderSmoothScale;
uint xrenderFilter() const {
return m_xrenderFilter;
}
qint64 maxFpsInterval() const {
@ -549,7 +549,7 @@ public:
void setCompositingInitialized(bool compositingInitialized);
void setHiddenPreviews(int hiddenPreviews);
void setUnredirectFullscreen(bool unredirectFullscreen);
void setXrenderSmoothScale(bool xrenderSmoothScale);
void setXrenderFilter(uint xrenderFilter);
void setMaxFpsInterval(qint64 maxFpsInterval);
void setRefreshRate(uint refreshRate);
void setVBlankTime(qint64 vBlankTime);
@ -624,8 +624,8 @@ public:
static bool defaultUnredirectFullscreen() {
return false;
}
static bool defaultXrenderSmoothScale() {
return false;
static uint defaultXrenderFilter() {
return 1;
}
static qint64 defaultMaxFpsInterval() {
return (1 * 1000 * 1000 * 1000) /60.0; // nanoseconds / Hz
@ -707,7 +707,7 @@ Q_SIGNALS:
void compositingInitializedChanged();
void hiddenPreviewsChanged();
void unredirectFullscreenChanged();
void xrenderSmoothScaleChanged();
void xrenderFilterChanged();
void maxFpsIntervalChanged();
void refreshRateChanged();
void vBlankTimeChanged();
@ -745,7 +745,7 @@ private:
bool m_compositingInitialized;
HiddenPreviews m_hiddenPreviews;
bool m_unredirectFullscreen;
bool m_xrenderSmoothScale;
uint m_xrenderFilter;
qint64 m_maxFpsInterval;
// Settings that should be auto-detected
uint m_refreshRate;

View file

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

View file

@ -93,7 +93,14 @@ public:
PAINT_SCREEN_BACKGROUND_FIRST = 1 << 6,
};
// 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)
virtual void idle();
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
return;
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
const QRect wr = mapToScreen(mask, data, QRect(0, 0, width(), height()));
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 {
xcb_render_set_picture_transform(connection(), pic, xform);
if (filter == ImageFilterGood) {
setPictureFilter(pic, KWin::Scene::ImageFilterGood);
}
setPictureFilter(pic, filter);
//BEGIN OF STUPID RADEON HACK
// 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) {
xcb_render_set_picture_transform(connection(), pic, identity);
if (filter == ImageFilterGood)
setPictureFilter(pic, KWin::Scene::ImageFilterFast);
if (!window()->hasAlpha()) {
const uint32_t values[] = {XCB_RENDER_REPEAT_NONE};
xcb_render_change_picture(connection(), pic, XCB_RENDER_CP_REPEAT, values);
@ -732,13 +718,33 @@ void SceneXrender::Window::setPictureFilter(xcb_render_picture_t pic, Scene::Ima
{
QByteArray filterName;
switch (filter) {
case KWin::Scene::ImageFilterFast:
case KWin::Scene::ImageFilterFast: {
filterName = QByteArray("fast");
break;
case KWin::Scene::ImageFilterGood:
}
case KWin::Scene::ImageFilterGood: {
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);
}