Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Plasma
KWin
Commits
faddf0bf
Commit
faddf0bf
authored
Feb 20, 2021
by
Xaver Hugl
Browse files
Wayland: variable refresh rate support
BUG: 405912
parent
2a6fe974
Changes
17
Hide whitespace changes
Inline
Side-by-side
src/abstract_wayland_output.cpp
View file @
faddf0bf
...
...
@@ -179,6 +179,10 @@ void AbstractWaylandOutput::applyChanges(const KWaylandServer::OutputChangeSet *
qCDebug
(
KWIN_CORE
)
<<
"Setting overscan:"
<<
changeSet
->
overscan
();
setOverscan
(
changeSet
->
overscan
());
}
if
(
changeSet
->
vrrPolicyChanged
())
{
qCDebug
(
KWIN_CORE
)
<<
"Setting VRR Policy:"
<<
changeSet
->
vrrPolicy
();
setVrrPolicy
(
static_cast
<
RenderLoop
::
VrrPolicy
>
(
changeSet
->
vrrPolicy
()));
}
overallSizeCheckNeeded
|=
emitModeChanged
;
if
(
overallSizeCheckNeeded
)
{
...
...
@@ -368,4 +372,17 @@ void AbstractWaylandOutput::setOverscan(uint32_t overscan)
Q_UNUSED
(
overscan
);
}
void
AbstractWaylandOutput
::
setVrrPolicy
(
RenderLoop
::
VrrPolicy
policy
)
{
if
(
renderLoop
()
->
vrrPolicy
()
!=
policy
)
{
renderLoop
()
->
setVrrPolicy
(
policy
);
emit
vrrPolicyChanged
();
}
}
RenderLoop
::
VrrPolicy
AbstractWaylandOutput
::
vrrPolicy
()
const
{
return
renderLoop
()
->
vrrPolicy
();
}
}
src/abstract_wayland_output.h
View file @
faddf0bf
...
...
@@ -11,6 +11,7 @@
#include "abstract_output.h"
#include "utils.h"
#include "renderloop.h"
#include <kwin_export.h>
#include <QObject>
...
...
@@ -66,6 +67,7 @@ public:
enum
class
Capability
:
uint
{
Dpms
=
0x1
,
Overscan
=
0x2
,
Vrr
=
0x4
,
};
Q_DECLARE_FLAGS
(
Capabilities
,
Capability
)
...
...
@@ -142,6 +144,9 @@ public:
bool
isBeingRecorded
();
void
setVrrPolicy
(
RenderLoop
::
VrrPolicy
policy
);
RenderLoop
::
VrrPolicy
vrrPolicy
()
const
;
Q_SIGNALS:
void
modeChanged
();
void
outputChange
(
const
QRegion
&
damagedRegion
);
...
...
@@ -150,6 +155,7 @@ Q_SIGNALS:
void
dpmsModeChanged
();
void
capabilitiesChanged
();
void
overscanChanged
();
void
vrrPolicyChanged
();
protected:
void
initialize
(
const
QString
&
model
,
const
QString
&
manufacturer
,
...
...
src/plugins/platforms/drm/drm_object_connector.cpp
View file @
faddf0bf
...
...
@@ -39,6 +39,7 @@ bool DrmConnector::init()
PropertyDefinition
(
QByteArrayLiteral
(
"DPMS"
)),
PropertyDefinition
(
QByteArrayLiteral
(
"EDID"
)),
PropertyDefinition
(
QByteArrayLiteral
(
"overscan"
)),
PropertyDefinition
(
QByteArrayLiteral
(
"vrr_capable"
)),
},
DRM_MODE_OBJECT_CONNECTOR
))
{
return
false
;
}
...
...
@@ -158,4 +159,12 @@ void DrmConnector::setOverscan(uint32_t overscan)
setValue
(
PropertyIndex
::
Overscan
,
overscan
);
}
bool
DrmConnector
::
vrrCapable
()
const
{
if
(
const
auto
&
prop
=
m_props
[
static_cast
<
int
>
(
PropertyIndex
::
VrrCapable
)])
{
return
prop
->
value
();
}
return
false
;
}
}
src/plugins/platforms/drm/drm_object_connector.h
View file @
faddf0bf
...
...
@@ -31,6 +31,7 @@ public:
Dpms
=
2
,
Edid
=
3
,
Overscan
=
4
,
VrrCapable
=
5
,
Count
};
...
...
@@ -66,6 +67,8 @@ public:
uint32_t
overscan
()
const
;
void
setOverscan
(
uint32_t
overscan
);
bool
vrrCapable
()
const
;
private:
DrmScopedPointer
<
drmModeConnector
>
m_conn
;
QVector
<
uint32_t
>
m_encoders
;
...
...
src/plugins/platforms/drm/drm_object_crtc.cpp
View file @
faddf0bf
...
...
@@ -33,6 +33,7 @@ bool DrmCrtc::init()
return
initProps
({
PropertyDefinition
(
QByteArrayLiteral
(
"MODE_ID"
)),
PropertyDefinition
(
QByteArrayLiteral
(
"ACTIVE"
)),
PropertyDefinition
(
QByteArrayLiteral
(
"VRR_ENABLED"
)),
},
DRM_MODE_OBJECT_CRTC
);
}
...
...
@@ -81,4 +82,30 @@ bool DrmCrtc::setGammaRamp(const GammaRamp &gamma)
return
!
isError
;
}
bool
DrmCrtc
::
setVrr
(
bool
enable
)
{
if
(
const
auto
&
prop
=
m_props
[
static_cast
<
int
>
(
PropertyIndex
::
VrrEnabled
)])
{
if
(
prop
->
value
()
==
enable
)
{
return
false
;
}
prop
->
setValue
(
enable
);
if
(
!
gpu
()
->
atomicModeSetting
()
||
gpu
()
->
useEglStreams
())
{
if
(
drmModeObjectSetProperty
(
gpu
()
->
fd
(),
id
(),
DRM_MODE_OBJECT_CRTC
,
prop
->
propId
(),
enable
)
!=
0
)
{
qCWarning
(
KWIN_DRM
)
<<
"drmModeObjectSetProperty(VRR_ENABLED) failed"
;
return
false
;
}
}
return
true
;
}
return
false
;
}
bool
DrmCrtc
::
isVrrEnabled
()
const
{
if
(
const
auto
&
prop
=
m_props
[
static_cast
<
int
>
(
PropertyIndex
::
VrrEnabled
)])
{
return
prop
->
value
();
}
return
false
;
}
}
src/plugins/platforms/drm/drm_object_crtc.h
View file @
faddf0bf
...
...
@@ -32,6 +32,7 @@ public:
enum
class
PropertyIndex
:
uint32_t
{
ModeId
=
0
,
Active
,
VrrEnabled
,
Count
};
...
...
@@ -60,6 +61,9 @@ public:
}
bool
setGammaRamp
(
const
GammaRamp
&
gamma
);
bool
setVrr
(
bool
enable
);
bool
isVrrEnabled
()
const
;
private:
DrmScopedPointer
<
drmModeCrtc
>
m_crtc
;
QSharedPointer
<
DrmBuffer
>
m_currentBuffer
;
...
...
src/plugins/platforms/drm/drm_output.cpp
View file @
faddf0bf
...
...
@@ -16,6 +16,7 @@
#include "logging.h"
#include "main.h"
#include "renderloop.h"
#include "renderloop_p.h"
#include "screens.h"
#include "session.h"
// Qt
...
...
@@ -76,13 +77,25 @@ void DrmOutput::teardown()
bool
DrmOutput
::
hideCursor
()
{
if
(
RenderLoopPrivate
::
get
(
m_renderLoop
)
->
presentMode
==
RenderLoopPrivate
::
SyncMode
::
Adaptive
&&
isCursorVisible
())
{
m_renderLoop
->
scheduleRepaint
();
}
return
drmModeSetCursor
(
m_gpu
->
fd
(),
m_crtc
->
id
(),
0
,
0
,
0
)
==
0
;
}
bool
DrmOutput
::
showCursor
(
DrmDumbBuffer
*
c
)
{
const
QSize
&
s
=
c
->
size
();
return
drmModeSetCursor
(
m_gpu
->
fd
(),
m_crtc
->
id
(),
c
->
handle
(),
s
.
width
(),
s
.
height
())
==
0
;
if
(
drmModeSetCursor
(
m_gpu
->
fd
(),
m_crtc
->
id
(),
c
->
handle
(),
s
.
width
(),
s
.
height
())
==
0
)
{
if
(
RenderLoopPrivate
::
get
(
m_renderLoop
)
->
presentMode
==
RenderLoopPrivate
::
SyncMode
::
Adaptive
&&
isCursorVisible
())
{
m_renderLoop
->
scheduleRepaint
();
}
return
true
;
}
else
{
return
false
;
}
}
bool
DrmOutput
::
showCursor
()
...
...
@@ -97,10 +110,16 @@ bool DrmOutput::showCursor()
return
ret
;
}
bool
visibleBefore
=
isCursorVisible
();
if
(
m_hasNewCursor
)
{
m_cursorIndex
=
(
m_cursorIndex
+
1
)
%
2
;
m_hasNewCursor
=
false
;
}
if
(
RenderLoopPrivate
::
get
(
m_renderLoop
)
->
presentMode
==
RenderLoopPrivate
::
SyncMode
::
Adaptive
&&
!
visibleBefore
&&
isCursorVisible
())
{
m_renderLoop
->
scheduleRepaint
();
}
return
ret
;
}
...
...
@@ -142,7 +161,10 @@ bool DrmOutput::updateCursor()
p
.
setWorldTransform
(
logicalToNativeMatrix
(
cursor
->
rect
(),
1
,
transform
()).
toTransform
());
p
.
drawImage
(
QPoint
(
0
,
0
),
cursorImage
);
p
.
end
();
if
(
RenderLoopPrivate
::
get
(
m_renderLoop
)
->
presentMode
==
RenderLoopPrivate
::
SyncMode
::
Adaptive
&&
isCursorVisible
())
{
m_renderLoop
->
scheduleRepaint
();
}
return
true
;
}
...
...
@@ -155,7 +177,15 @@ void DrmOutput::moveCursor()
QPoint
pos
=
monitorMatrix
.
map
(
cursor
->
pos
());
pos
-=
hotspotMatrix
.
map
(
cursor
->
hotspot
());
drmModeMoveCursor
(
m_gpu
->
fd
(),
m_crtc
->
id
(),
pos
.
x
(),
pos
.
y
());
if
(
pos
!=
m_cursorPos
)
{
bool
visible
=
isCursorVisible
();
drmModeMoveCursor
(
m_gpu
->
fd
(),
m_crtc
->
id
(),
pos
.
x
(),
pos
.
y
());
m_cursorPos
=
pos
;
if
(
RenderLoopPrivate
::
get
(
m_renderLoop
)
->
presentMode
==
RenderLoopPrivate
::
SyncMode
::
Adaptive
&&
(
visible
||
visible
!=
isCursorVisible
()))
{
m_renderLoop
->
scheduleRepaint
();
}
}
}
namespace
{
...
...
@@ -210,6 +240,10 @@ bool DrmOutput::init(drmModeConnector *connector)
setCapabilityInternal
(
Capability
::
Overscan
);
setOverscanInternal
(
m_conn
->
overscan
());
}
if
(
m_conn
->
vrrCapable
())
{
setCapabilityInternal
(
Capability
::
Vrr
);
setVrrPolicy
(
RenderLoop
::
VrrPolicy
::
Automatic
);
}
initOutputDevice
(
connector
);
if
(
!
m_gpu
->
atomicModeSetting
()
&&
!
m_crtc
->
blank
(
this
))
{
...
...
@@ -564,6 +598,8 @@ bool DrmOutput::present(const QSharedPointer<DrmBuffer> &buffer)
if
(
m_dpmsModePending
!=
DpmsMode
::
On
)
{
return
false
;
}
RenderLoopPrivate
*
renderLoopPrivate
=
RenderLoopPrivate
::
get
(
m_renderLoop
);
setVrr
(
renderLoopPrivate
->
presentMode
==
RenderLoopPrivate
::
SyncMode
::
Adaptive
);
return
m_gpu
->
atomicModeSetting
()
?
presentAtomically
(
buffer
)
:
presentLegacy
(
buffer
);
}
...
...
@@ -747,6 +783,12 @@ bool DrmOutput::doAtomicCommit(AtomicCommitMode mode)
flags
|=
DRM_MODE_ATOMIC_ALLOW_MODESET
;
}
if
(
!
m_crtc
->
atomicPopulate
(
req
))
{
qCWarning
(
KWIN_DRM
)
<<
"Failed to populate crtc. Abort atomic commit!"
;
errorHandler
();
return
false
;
}
if
(
mode
==
AtomicCommitMode
::
Real
)
{
if
(
m_dpmsModePending
==
DpmsMode
::
On
)
{
if
(
!
(
flags
&
DRM_MODE_ATOMIC_ALLOW_MODESET
))
{
...
...
@@ -834,11 +876,7 @@ bool DrmOutput::atomicReqModesetPopulate(drmModeAtomicReq *req, bool enable)
m_crtc
->
setValue
(
DrmCrtc
::
PropertyIndex
::
ModeId
,
enable
?
m_blobId
:
0
);
m_crtc
->
setValue
(
DrmCrtc
::
PropertyIndex
::
Active
,
enable
);
bool
ret
=
true
;
ret
&=
m_conn
->
atomicPopulate
(
req
);
ret
&=
m_crtc
->
atomicPopulate
(
req
);
return
ret
;
return
m_conn
->
atomicPopulate
(
req
);
}
int
DrmOutput
::
gammaRampSize
()
const
...
...
@@ -859,4 +897,21 @@ void DrmOutput::setOverscan(uint32_t overscan)
}
}
void
DrmOutput
::
setVrr
(
bool
enable
)
{
if
(
!
m_conn
->
vrrCapable
()
||
m_crtc
->
isVrrEnabled
()
==
enable
)
{
return
;
}
if
(
!
m_crtc
->
setVrr
(
enable
)
||
(
m_gpu
->
atomicModeSetting
()
&&
!
doAtomicCommit
(
AtomicCommitMode
::
Test
)))
{
qCWarning
(
KWIN_DRM
)
<<
"Failed to set vrr on"
<<
this
;
setVrrPolicy
(
RenderLoop
::
VrrPolicy
::
Never
);
m_crtc
->
setVrr
(
false
);
}
}
bool
DrmOutput
::
isCursorVisible
()
{
return
m_cursor
[
m_cursorIndex
]
&&
QRect
(
m_cursorPos
,
m_cursor
[
m_cursorIndex
]
->
size
()).
intersects
(
QRect
(
0
,
0
,
m_mode
.
vdisplay
,
m_mode
.
hdisplay
));
}
}
src/plugins/platforms/drm/drm_output.h
View file @
faddf0bf
...
...
@@ -129,6 +129,9 @@ private:
bool
setGammaRamp
(
const
GammaRamp
&
gamma
)
override
;
void
setOverscan
(
uint32_t
overscan
)
override
;
void
setVrr
(
bool
enable
);
bool
isCursorVisible
();
DrmBackend
*
m_backend
;
DrmGpu
*
m_gpu
;
DrmConnector
*
m_conn
=
nullptr
;
...
...
@@ -141,6 +144,8 @@ private:
uint32_t
m_blobId
=
0
;
DrmPlane
*
m_primaryPlane
=
nullptr
;
QVector
<
DrmPlane
*>
m_nextPlanesFlipList
;
QPoint
m_cursorPos
;
bool
m_pageFlipPending
=
false
;
bool
m_atomicOffPending
=
false
;
bool
m_modesetRequested
=
true
;
...
...
src/plugins/scenes/opengl/scene_opengl.cpp
View file @
faddf0bf
...
...
@@ -644,41 +644,42 @@ void SceneOpenGL::paint(int screenId, const QRegion &damage, const QList<Topleve
}
else
{
renderLoop
->
beginFrame
();
bool
directScanout
=
false
;
if
(
m_backend
->
directScanoutAllowed
(
screenId
))
{
EffectsHandlerImpl
*
implEffects
=
static_cast
<
EffectsHandlerImpl
*>
(
effects
);
if
(
!
implEffects
->
blocksDirectScanout
())
{
for
(
int
i
=
stacking_order
.
count
()
-
1
;
i
>=
0
;
i
--
)
{
Window
*
window
=
stacking_order
[
i
];
Toplevel
*
toplevel
=
window
->
window
();
if
(
toplevel
->
isOnScreen
(
screenId
)
&&
window
->
isVisible
()
&&
toplevel
->
opacity
()
>
0
)
{
AbstractClient
*
c
=
dynamic_cast
<
AbstractClient
*>
(
toplevel
);
if
(
!
c
||
!
c
->
isFullScreen
())
{
break
;
}
if
(
!
window
->
surfaceItem
())
{
continue
;
}
SurfaceItem
*
topMost
=
findTopMostSurface
(
window
->
surfaceItem
());
auto
pixmap
=
topMost
->
windowPixmap
();
if
(
!
pixmap
)
{
break
;
}
pixmap
->
update
();
// the subsurface has to be able to cover the whole window
if
(
topMost
->
position
()
!=
QPoint
(
0
,
0
))
{
break
;
}
// and it has to be completely opaque
if
(
!
window
->
isOpaque
()
&&
!
topMost
->
opaque
().
contains
(
QRect
(
0
,
0
,
window
->
width
(),
window
->
height
())))
{
break
;
}
directScanout
=
m_backend
->
scanout
(
screenId
,
topMost
);
break
;
}
SurfaceItem
*
fullscreenSurface
=
nullptr
;
for
(
int
i
=
stacking_order
.
count
()
-
1
;
i
>=
0
;
i
--
)
{
Window
*
window
=
stacking_order
[
i
];
Toplevel
*
toplevel
=
window
->
window
();
if
(
toplevel
->
isOnScreen
(
screenId
)
&&
window
->
isVisible
()
&&
toplevel
->
opacity
()
>
0
)
{
AbstractClient
*
c
=
dynamic_cast
<
AbstractClient
*>
(
toplevel
);
if
(
!
c
||
!
c
->
isFullScreen
())
{
break
;
}
if
(
!
window
->
surfaceItem
())
{
break
;
}
SurfaceItem
*
topMost
=
findTopMostSurface
(
window
->
surfaceItem
());
auto
pixmap
=
topMost
->
windowPixmap
();
if
(
!
pixmap
)
{
break
;
}
pixmap
->
update
();
// the subsurface has to be able to cover the whole window
if
(
topMost
->
position
()
!=
QPoint
(
0
,
0
))
{
break
;
}
// and it has to be completely opaque
if
(
!
window
->
isOpaque
()
&&
!
topMost
->
opaque
().
contains
(
QRect
(
0
,
0
,
window
->
width
(),
window
->
height
())))
{
break
;
}
fullscreenSurface
=
topMost
;
break
;
}
}
renderLoop
->
setFullscreenSurface
(
fullscreenSurface
);
bool
directScanout
=
false
;
if
(
m_backend
->
directScanoutAllowed
(
screenId
)
&&
!
static_cast
<
EffectsHandlerImpl
*>
(
effects
)
->
blocksDirectScanout
())
{
directScanout
=
m_backend
->
scanout
(
screenId
,
fullscreenSurface
);
}
if
(
directScanout
)
{
renderLoop
->
endFrame
();
}
else
{
...
...
src/renderloop.cpp
View file @
faddf0bf
...
...
@@ -8,6 +8,7 @@
#include "options.h"
#include "renderloop_p.h"
#include "utils.h"
#include "surfaceitem.h"
namespace
KWin
{
...
...
@@ -32,12 +33,30 @@ RenderLoopPrivate::RenderLoopPrivate(RenderLoop *q)
void
RenderLoopPrivate
::
scheduleRepaint
()
{
if
(
compositeTimer
.
isActive
()
||
kwinApp
()
->
isTerminating
())
{
if
(
kwinApp
()
->
isTerminating
())
{
return
;
}
if
(
vrrPolicy
==
RenderLoop
::
VrrPolicy
::
Always
||
(
vrrPolicy
==
RenderLoop
::
VrrPolicy
::
Automatic
&&
hasFullscreenSurface
))
{
presentMode
=
SyncMode
::
Adaptive
;
}
else
{
presentMode
=
SyncMode
::
Fixed
;
}
const
std
::
chrono
::
nanoseconds
vblankInterval
(
1'000'000'000'000ull
/
refreshRate
);
if
(
presentMode
==
SyncMode
::
Adaptive
)
{
std
::
chrono
::
nanoseconds
timeSincePresent
=
std
::
chrono
::
steady_clock
::
now
().
time_since_epoch
()
-
lastPresentationTimestamp
;
if
(
timeSincePresent
>
vblankInterval
)
{
// client renders slower than refresh rate -> immediately present
compositeTimer
.
start
(
0
);
return
;
}
// client renders faster than refresh rate -> normal frame scheduling
}
if
(
compositeTimer
.
isActive
())
{
return
;
}
const
std
::
chrono
::
nanoseconds
currentTime
(
std
::
chrono
::
steady_clock
::
now
().
time_since_epoch
());
const
std
::
chrono
::
nanoseconds
vblankInterval
(
1'000'000'000'000ull
/
refreshRate
);
// Estimate when the next presentation will occur. Note that this is a prediction.
nextPresentationTimestamp
=
lastPresentationTimestamp
+
vblankInterval
;
...
...
@@ -231,4 +250,19 @@ std::chrono::nanoseconds RenderLoop::nextPresentationTimestamp() const
return
d
->
nextPresentationTimestamp
;
}
void
RenderLoop
::
setFullscreenSurface
(
SurfaceItem
*
surfaceItem
)
{
d
->
hasFullscreenSurface
=
surfaceItem
!=
nullptr
;
}
RenderLoop
::
VrrPolicy
RenderLoop
::
vrrPolicy
()
const
{
return
d
->
vrrPolicy
;
}
void
RenderLoop
::
setVrrPolicy
(
VrrPolicy
policy
)
{
d
->
vrrPolicy
=
policy
;
}
}
// namespace KWin
src/renderloop.h
View file @
faddf0bf
...
...
@@ -14,6 +14,7 @@ namespace KWin
{
class
RenderLoopPrivate
;
class
SurfaceItem
;
/**
* The RenderLoop class represents the compositing scheduler on a particular output.
...
...
@@ -85,6 +86,29 @@ public:
*/
std
::
chrono
::
nanoseconds
nextPresentationTimestamp
()
const
;
/**
* Sets the surface that currently gets scanned out,
* so that this RenderLoop can adjust its timing behavior to that surface
*/
void
setFullscreenSurface
(
SurfaceItem
*
surface
);
enum
class
VrrPolicy
:
uint32_t
{
Never
=
0
,
Always
=
1
,
Automatic
=
2
,
};
Q_ENUM
(
VrrPolicy
);
/**
* the current policy regarding the use of variable refresh rate
*/
VrrPolicy
vrrPolicy
()
const
;
/**
* Set the policy regarding the use of variable refresh rate with RenderLoop
*/
void
setVrrPolicy
(
VrrPolicy
vrrPolicy
);
Q_SIGNALS:
/**
* This signal is emitted when the refresh rate of this RenderLoop has changed.
...
...
src/renderloop_p.h
View file @
faddf0bf
...
...
@@ -40,6 +40,14 @@ public:
int
inhibitCount
=
0
;
bool
pendingReschedule
=
false
;
bool
pendingRepaint
=
false
;
RenderLoop
::
VrrPolicy
vrrPolicy
=
RenderLoop
::
VrrPolicy
::
Never
;
bool
hasFullscreenSurface
=
false
;
enum
class
SyncMode
{
Fixed
,
Adaptive
,
};
SyncMode
presentMode
=
SyncMode
::
Fixed
;
};
}
// namespace KWin
src/screens.cpp
View file @
faddf0bf
...
...
@@ -17,6 +17,7 @@
#include <config-kwin.h>
#include "platform.h"
#include "wayland_server.h"
#include "abstract_wayland_output.h"
#ifdef KWIN_UNIT_TEST
#include <mock_screens.h>
#endif
...
...
@@ -256,6 +257,34 @@ int Screens::physicalDpiY(int screen) const
return
size
(
screen
).
height
()
/
physicalSize
(
screen
).
height
()
*
qreal
(
25.4
);
}
bool
Screens
::
isVrrCapable
(
int
screen
)
const
{
#ifdef KWIN_UNIT_TEST
Q_UNUSED
(
screen
);
return
false
;
#else
if
(
auto
output
=
findOutput
(
screen
))
{
if
(
auto
waylandoutput
=
dynamic_cast
<
AbstractWaylandOutput
*>
(
output
))
{
return
waylandoutput
->
capabilities
()
&
AbstractWaylandOutput
::
Capability
::
Vrr
;
}
}
#endif
return
true
;
}
RenderLoop
::
VrrPolicy
Screens
::
vrrPolicy
(
int
screen
)
const
{
#ifdef KWIN_UNIT_TEST
Q_UNUSED
(
screen
);
return
RenderLoop
::
VrrPolicy
::
Never
;
#else
if
(
auto
output
=
findOutput
(
screen
))
{
return
output
->
renderLoop
()
->
vrrPolicy
();
}
return
RenderLoop
::
VrrPolicy
::
Never
;
#endif
}
int
Screens
::
number
(
const
QPoint
&
pos
)
const
{
// TODO: Do something about testScreens and other tests that use MockScreens.
...
...
src/screens.h
View file @
faddf0bf
...
...
@@ -11,6 +11,7 @@
// KWin includes
#include <kwinglobals.h>
#include <renderloop.h>
// KDE includes
#include <KConfig>
#include <KSharedConfig>
...
...
@@ -131,6 +132,15 @@ public:
int
physicalDpiX
(
int
screen
)
const
;
int
physicalDpiY
(
int
screen
)
const
;
/**
* @returns @c true if the @p screen is capable of variable refresh rate and if the platform can use it
*/
bool
isVrrCapable
(
int
screen
)
const
;
/**
* @returns the vrr policy of the @p screen
*/
RenderLoop
::
VrrPolicy
vrrPolicy
(
int
screen
)
const
;
public
Q_SLOTS
:
void
reconfigure
();
...
...
src/waylandoutputdevice.cpp
View file @
faddf0bf
...
...
@@ -26,9 +26,17 @@ static KWaylandServer::OutputDeviceInterface::Capabilities kwinCapabilitiesToOut
if
(
caps
&
AbstractWaylandOutput
::
Capability
::
Overscan
)
{
ret
|=
KWaylandServer
::
OutputDeviceInterface
::
Capability
::
Overscan
;
}
if
(
caps
&
AbstractWaylandOutput
::
Capability
::
Vrr
)
{
ret
|=
KWaylandServer
::
OutputDeviceInterface
::
Capability
::
Vrr
;
}
return
ret
;
}
static
KWaylandServer
::
OutputDeviceInterface
::
VrrPolicy
kwinVrrPolicyToOutputDeviceVrrPolicy
(
RenderLoop
::
VrrPolicy
policy
)
{
return
static_cast
<
KWaylandServer
::
OutputDeviceInterface
::
VrrPolicy
>
(
policy
);
}
WaylandOutputDevice
::
WaylandOutputDevice
(
AbstractWaylandOutput
*
output
,
QObject
*
parent
)
:
QObject
(
parent
)
,
m_platformOutput
(
output
)
...
...
@@ -47,6 +55,7 @@ WaylandOutputDevice::WaylandOutputDevice(AbstractWaylandOutput *output, QObject
m_outputDevice
->
setSubPixel
(
kwinSubPixelToOutputDeviceSubPixel
(
output
->
subPixel
()));
m_outputDevice
->
setOverscan
(
output
->
overscan
());
m_outputDevice
->
setCapabilities
(
kwinCapabilitiesToOutputDeviceCapabilities
(
output
->
capabilities
()));
m_outputDevice
->
setVrrPolicy
(
kwinVrrPolicyToOutputDeviceVrrPolicy
(
output
->
vrrPolicy
()));
const
auto
modes
=
output
->
modes
();
for
(
const
AbstractWaylandOutput
::
Mode
&
mode
:
modes
)
{
...
...
@@ -79,6 +88,8 @@ WaylandOutputDevice::WaylandOutputDevice(AbstractWaylandOutput *output, QObject
this
,
&
WaylandOutputDevice
::
handleCapabilitiesChanged
);
connect
(
output
,
&
AbstractWaylandOutput
::
overscanChanged
,
this
,
&
WaylandOutputDevice
::
handleOverscanChanged
);
connect
(
output
,
&
AbstractWaylandOutput
::
vrrPolicyChanged
,
this
,
&
WaylandOutputDevice
::
handleVrrPolicyChanged
);
}