Fix rendering so that moving the cursor doesn't cause the whole screen to rerender
This commit is contained in:
parent
638105667e
commit
205c80445a
|
|
@ -67,4 +67,6 @@ target_link_libraries(breezy_desktop
|
|||
)
|
||||
|
||||
|
||||
install(DIRECTORY qml DESTINATION ${KDE_INSTALL_DATADIR}/kwin/effects/breezy_desktop)
|
||||
install(DIRECTORY qml DESTINATION ${KDE_INSTALL_DATADIR}/kwin/effects/breezy_desktop)
|
||||
install(FILES qml/cursorOverlay.frag DESTINATION ${KDE_INSTALL_DATADIR}/kwin/effects/breezy_desktop/qml)
|
||||
install(FILES qml/cursorOverlay.vert DESTINATION ${KDE_INSTALL_DATADIR}/kwin/effects/breezy_desktop/qml)
|
||||
|
|
@ -540,6 +540,11 @@ QString BreezyDesktopEffect::cursorImageSource() const
|
|||
return m_cursorImageSource;
|
||||
}
|
||||
|
||||
QSize BreezyDesktopEffect::cursorImageSize() const
|
||||
{
|
||||
return m_cursorImageSize;
|
||||
}
|
||||
|
||||
QPointF BreezyDesktopEffect::cursorPos() const
|
||||
{
|
||||
return m_cursorPos;
|
||||
|
|
@ -566,10 +571,12 @@ void BreezyDesktopEffect::updateCursorImage()
|
|||
cursor.image().save(&buffer, "PNG");
|
||||
|
||||
m_cursorImageSource = QStringLiteral("data:image/png;base64,%1").arg(QString::fromLatin1(data.toBase64()));
|
||||
m_cursorImageSize = cursor.image().size();
|
||||
} else {
|
||||
m_cursorImageSource = QString();
|
||||
m_cursorImageSize = QSize();
|
||||
}
|
||||
Q_EMIT cursorImageChanged();
|
||||
Q_EMIT cursorImageSourceChanged();
|
||||
}
|
||||
|
||||
void BreezyDesktopEffect::updateCursorPos()
|
||||
|
|
|
|||
|
|
@ -16,11 +16,12 @@ namespace KWin
|
|||
Q_OBJECT
|
||||
Q_PROPERTY(bool isEnabled READ isEnabled NOTIFY enabledStateChanged)
|
||||
Q_PROPERTY(bool zoomOnFocusEnabled READ isZoomOnFocusEnabled WRITE setZoomOnFocusEnabled NOTIFY zoomOnFocusChanged)
|
||||
Q_PROPERTY(bool imuResetState READ imuResetState NOTIFY imuRotationsChanged)
|
||||
Q_PROPERTY(QList<QQuaternion> imuRotations READ imuRotations NOTIFY imuRotationsChanged)
|
||||
Q_PROPERTY(quint32 imuTimeElapsedMs READ imuTimeElapsedMs NOTIFY imuRotationsChanged)
|
||||
Q_PROPERTY(quint64 imuTimestamp READ imuTimestamp NOTIFY imuRotationsChanged)
|
||||
Q_PROPERTY(QString cursorImageSource READ cursorImageSource NOTIFY cursorImageChanged)
|
||||
Q_PROPERTY(bool imuResetState READ imuResetState)
|
||||
Q_PROPERTY(QList<QQuaternion> imuRotations READ imuRotations)
|
||||
Q_PROPERTY(quint32 imuTimeElapsedMs READ imuTimeElapsedMs)
|
||||
Q_PROPERTY(quint64 imuTimestamp READ imuTimestamp)
|
||||
Q_PROPERTY(QString cursorImageSource READ cursorImageSource NOTIFY cursorImageSourceChanged)
|
||||
Q_PROPERTY(QSize cursorImageSize READ cursorImageSize NOTIFY cursorImageSourceChanged)
|
||||
Q_PROPERTY(QPointF cursorPos READ cursorPos NOTIFY cursorPosChanged)
|
||||
Q_PROPERTY(QList<qreal> lookAheadConfig READ lookAheadConfig NOTIFY devicePropertiesChanged)
|
||||
Q_PROPERTY(QList<quint32> displayResolution READ displayResolution NOTIFY devicePropertiesChanged)
|
||||
|
|
@ -44,6 +45,7 @@ namespace KWin
|
|||
int requestedEffectChainPosition() const override;
|
||||
|
||||
QString cursorImageSource() const;
|
||||
QSize cursorImageSize() const;
|
||||
QPointF cursorPos() const;
|
||||
|
||||
bool isEnabled() const;
|
||||
|
|
@ -91,7 +93,7 @@ namespace KWin
|
|||
void enabledStateChanged();
|
||||
void zoomOnFocusChanged();
|
||||
void imuRotationsChanged();
|
||||
void cursorImageChanged();
|
||||
void cursorImageSourceChanged();
|
||||
void cursorPosChanged();
|
||||
void devicePropertiesChanged();
|
||||
|
||||
|
|
@ -107,6 +109,7 @@ namespace KWin
|
|||
|
||||
QTimer *m_shutdownTimer;
|
||||
QString m_cursorImageSource;
|
||||
QSize m_cursorImageSize;
|
||||
|
||||
bool m_enabled = false;
|
||||
bool m_zoomOnFocusEnabled = false;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ Node {
|
|||
property var screens: root.screens
|
||||
property var fovDetails: root.fovDetails
|
||||
property var monitorPlacements: root.monitorPlacements
|
||||
property var imuRotations: effect.imuRotations
|
||||
property int focusedMonitorIndex: -1
|
||||
|
||||
Displays {
|
||||
|
|
@ -29,10 +28,17 @@ Node {
|
|||
delegate: BreezyDesktopDisplay {
|
||||
screen: breezyDesktop.screens[index]
|
||||
monitorPlacement: breezyDesktop.monitorPlacements[index]
|
||||
|
||||
property real monitorDistance: effect.allDisplaysDistance
|
||||
property real targetDistance: effect.allDisplaysDistance
|
||||
property real screenRotationY: displays.radianToDegree(monitorPlacement.rotationAngleRadians.y)
|
||||
property real screenRotationX: displays.radianToDegree(monitorPlacement.rotationAngleRadians.x)
|
||||
property matrix4x4 rotationMatrix: {
|
||||
const matrix = Qt.matrix4x4();
|
||||
matrix.rotate(screenRotationY, Qt.vector3d(0, 1, 0));
|
||||
matrix.rotate(screenRotationX, Qt.vector3d(1, 0, 0));
|
||||
return matrix;
|
||||
}
|
||||
|
||||
property vector3d screenScale: {
|
||||
const geometry = screen.geometry;
|
||||
|
|
@ -45,19 +51,12 @@ Node {
|
|||
eulerRotation.y: screenRotationY
|
||||
eulerRotation.x: screenRotationX
|
||||
position: {
|
||||
// camera looks along the negative Z axis
|
||||
const positionVector =
|
||||
displays.nwuToEusVector(monitorPlacement.centerNoRotate)
|
||||
.times(monitorDistance / effect.allDisplaysDistance);
|
||||
const displayNwu =
|
||||
monitorPlacement.centerNoRotate
|
||||
.times(monitorDistance / effect.allDisplaysDistance);
|
||||
|
||||
// position vector is only translated in flat directions, without rotations applied, so apply them here
|
||||
const rotationMatrix = Qt.matrix4x4();
|
||||
|
||||
// only one of these should ever be non-zero, since we only rotate in the direction of the "wrap" preference
|
||||
rotationMatrix.rotate(screenRotationY, Qt.vector3d(0, 1, 0));
|
||||
rotationMatrix.rotate(screenRotationX, Qt.vector3d(1, 0, 0));
|
||||
|
||||
return rotationMatrix.times(positionVector);
|
||||
return rotationMatrix.times(displays.nwuToEusVector(displayNwu));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -67,12 +66,12 @@ Node {
|
|||
repeat: true
|
||||
running: true
|
||||
onTriggered: {
|
||||
if (breezyDesktop.imuRotations && breezyDesktop.imuRotations.length > 0) {
|
||||
if (effect.imuRotations && effect.imuRotations.length > 0) {
|
||||
let focusedIndex = -1;
|
||||
|
||||
if (effect.zoomOnFocusEnabled) {
|
||||
focusedIndex = displays.findFocusedMonitor(
|
||||
displays.eusToNwuQuat(breezyDesktop.imuRotations[0]),
|
||||
displays.eusToNwuQuat(effect.imuRotations[0]),
|
||||
breezyDesktop.monitorPlacements.map(monitorVectors => monitorVectors.centerLook),
|
||||
breezyDesktop.focusedMonitorIndex,
|
||||
false, // TODO smooth follow
|
||||
|
|
|
|||
|
|
@ -8,19 +8,46 @@ Model {
|
|||
required property var monitorPlacement
|
||||
required property int index
|
||||
|
||||
property string cursorImageSource: effect.cursorImageSource
|
||||
property size cursorImageSize: effect.cursorImageSize
|
||||
property point cursorPos: effect.cursorPos
|
||||
|
||||
source: "#Rectangle"
|
||||
materials: [
|
||||
DefaultMaterial {
|
||||
cullMode: Material.NoCulling
|
||||
lighting: DefaultMaterial.NoLighting
|
||||
depthDrawMode: Material.AlwaysDepthDraw
|
||||
diffuseMap: Texture {
|
||||
sourceItem: DesktopView {
|
||||
screen: display.screen
|
||||
width: display.screen.geometry.width
|
||||
height: display.screen.geometry.height
|
||||
CustomMaterial {
|
||||
id: customMat
|
||||
depthDrawMode: CustomMaterial.AlwaysDepthDraw
|
||||
shadingMode: CustomMaterial.Unshaded
|
||||
|
||||
property real screenWidth: display.screen.geometry.width
|
||||
property real screenHeight: display.screen.geometry.height
|
||||
property real cursorX: display.cursorPos.x - display.screen.geometry.x
|
||||
property real cursorY: display.cursorPos.y - display.screen.geometry.y
|
||||
property real cursorW: display.cursorImageSize.width
|
||||
property real cursorH: display.cursorImageSize.height
|
||||
property bool showCursor: cursorX >= 0 && cursorX < screenWidth && cursorY >= 0 && cursorY < screenHeight
|
||||
|
||||
property TextureInput desktopTex: TextureInput {
|
||||
texture: Texture {
|
||||
sourceItem: DesktopView {
|
||||
screen: display.screen
|
||||
width: display.screen.geometry.width
|
||||
height: display.screen.geometry.height
|
||||
}
|
||||
}
|
||||
}
|
||||
property TextureInput cursorTex: TextureInput {
|
||||
texture: Texture {
|
||||
sourceItem: Image {
|
||||
source: effect.cursorImageSource
|
||||
width: effect.cursorImageSize.width
|
||||
height: effect.cursorImageSize.height
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fragmentShader: "cursorOverlay.frag"
|
||||
vertexShader: "cursorOverlay.vert"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,10 +6,6 @@ Item {
|
|||
|
||||
required property Camera camera
|
||||
|
||||
property var imuRotations: effect.imuRotations
|
||||
property int imuTimeElapsedMs: effect.imuTimeElapsedMs
|
||||
property double imuTimestamp: effect.imuTimestamp
|
||||
property var lookAheadConfig: effect.lookAheadConfig
|
||||
property var displayResolution: effect.displayResolution
|
||||
property real diagonalFOV: effect.diagonalFOV
|
||||
property real lensDistanceRatio: effect.lensDistanceRatio
|
||||
|
|
@ -67,14 +63,18 @@ Item {
|
|||
|
||||
onDisplayResolutionChanged: updateFOV();
|
||||
onDiagonalFOVChanged: updateFOV();
|
||||
onImuRotationsChanged: {
|
||||
if (root.imuRotations && root.imuRotations.length > 0) {
|
||||
updateCamera(applyLookAhead(
|
||||
root.imuRotations[0],
|
||||
root.imuRotations[1],
|
||||
root.imuTimeElapsedMs,
|
||||
lookAheadMS(root.imuTimestamp, root.lookAheadConfig, -1)
|
||||
));
|
||||
|
||||
FrameAnimation {
|
||||
running: true
|
||||
onTriggered: {
|
||||
if (effect.imuRotations && effect.imuRotations.length > 0) {
|
||||
updateCamera(applyLookAhead(
|
||||
effect.imuRotations[0],
|
||||
effect.imuRotations[1],
|
||||
effect.imuTimeElapsedMs,
|
||||
lookAheadMS(effect.imuTimestamp, effect.lookAheadConfig, -1)
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,18 +40,4 @@ Item {
|
|||
visible: onThisScreen && !model.window.minimized
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
id: cursorImg
|
||||
source: effect.cursorImageSource
|
||||
cache: false
|
||||
visible: true // TODO - cursor position bounds check?
|
||||
x: effect.cursorPos.x - desktopView.screen.geometry.x
|
||||
y: effect.cursorPos.y - desktopView.screen.geometry.y
|
||||
z: 9999 // ensure on top
|
||||
anchors.centerIn: undefined
|
||||
|
||||
layer.enabled: true
|
||||
layer.smooth: true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: singleDesktopView
|
||||
property point cursorPos: effect.cursorPos
|
||||
|
||||
function cursorInBounds() {
|
||||
const x = cursorPos.x
|
||||
const y = cursorPos.y
|
||||
const screenGeom = targetScreen.geometry
|
||||
return x >= screenGeom.x &&
|
||||
x < screenGeom.x + screenGeom.width &&
|
||||
y >= screenGeom.y &&
|
||||
y < screenGeom.y + screenGeom.height
|
||||
}
|
||||
|
||||
DesktopView {
|
||||
screen: targetScreen
|
||||
width: targetScreen.geometry.width
|
||||
height: targetScreen.geometry.height
|
||||
}
|
||||
|
||||
Image {
|
||||
id: cursorImg
|
||||
x: 0
|
||||
y: 0
|
||||
z: 9999 // ensure on top
|
||||
}
|
||||
|
||||
onCursorPosChanged: {
|
||||
if (singleDesktopView.cursorInBounds()) {
|
||||
const newX = effect.cursorPos.x - targetScreen.geometry.x
|
||||
const newY = effect.cursorPos.y - targetScreen.geometry.y
|
||||
const newSrc = effect.cursorImageSource
|
||||
if (cursorImg.x !== newX) cursorImg.x = newX
|
||||
if (cursorImg.y !== newY) cursorImg.y = newY
|
||||
if (cursorImg.source !== newSrc) cursorImg.source = newSrc
|
||||
if (!cursorImg.visible) cursorImg.visible = true
|
||||
} else if (cursorImg.visible) {
|
||||
cursorImg.visible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
VARYING vec3 pos;
|
||||
VARYING vec2 texcoord;
|
||||
|
||||
void MAIN() {
|
||||
vec2 tex = vec2(texcoord.x, 1.0 - texcoord.y);
|
||||
vec4 color = texture(desktopTex, tex);
|
||||
if (showCursor) {
|
||||
vec2 fragCoord = tex * vec2(screenWidth, screenHeight);
|
||||
vec2 cursorTopLeft = vec2(cursorX, cursorY);
|
||||
vec2 cursorBottomRight = cursorTopLeft + vec2(cursorW, cursorH);
|
||||
if (fragCoord.x >= cursorTopLeft.x && fragCoord.x < cursorBottomRight.x && fragCoord.y >= cursorTopLeft.y && fragCoord.y < cursorBottomRight.y) {
|
||||
vec2 rel = (fragCoord - cursorTopLeft) / vec2(cursorW, cursorH);
|
||||
vec4 cursorCol = texture(cursorTex, rel);
|
||||
color = mix(color, cursorCol, cursorCol.a);
|
||||
}
|
||||
}
|
||||
FRAGCOLOR = color;
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
VARYING vec3 pos;
|
||||
VARYING vec2 texcoord;
|
||||
|
||||
// this is a no-op vertex shader, CustomMaterial required one
|
||||
void MAIN()
|
||||
{
|
||||
pos = VERTEX;
|
||||
texcoord = UV0;
|
||||
POSITION = MODELVIEWPROJECTION_MATRIX * vec4(pos, 1.0);
|
||||
}
|
||||
|
|
@ -89,11 +89,7 @@ Item {
|
|||
|
||||
Component {
|
||||
id: desktopViewComponent
|
||||
DesktopView {
|
||||
screen: root.targetScreen
|
||||
width: root.targetScreen.geometry.width
|
||||
height: root.targetScreen.geometry.height
|
||||
}
|
||||
SingleDesktopView {}
|
||||
}
|
||||
|
||||
Component {
|
||||
|
|
|
|||
Loading…
Reference in New Issue