Compare commits

...

173 Commits

Author SHA1 Message Date
Geoffrey McRae
e31874b809 [resources] update update minimum cmake version required 2023-11-10 06:28:06 +11:00
Geoffrey McRae
a2443cf926 [client] wayland: libdecor is not a requirement of building 2023-11-10 06:28:06 +11:00
Geoffrey McRae
eaaef65791 [repo] update PureSpice and nanosvg 2023-11-10 06:28:06 +11:00
Geoffrey McRae
11542d7ace [repos] update LGMP submodule 2023-11-10 06:28:06 +11:00
Geoffrey McRae
138a0aee53 [all] update cmake minimum version 2023-11-10 06:28:05 +11:00
Geoffrey McRae
7a30736ac4 [host] linux: fix compilation (untested) 2023-11-10 06:28:05 +11:00
Geoffrey McRae
174b51b144 [client] wayland: add additional debug output 2023-11-10 06:28:05 +11:00
Geoffrey McRae
aa9dbe654d [client] wayland: move libdecor and xdg into seperate backends
This allows us to build with libdecor enabled as the selection to use it
is decided upon at runtime if the compositor `gnome-shell` is detected.
If the libdecor development headers are installed, by default it will
now be compiled in unless overridden by the user at compile time.
2023-11-10 06:28:05 +11:00
Geoffrey McRae
d592f13f88 [host] all: don't combine the downsampler rules 2023-11-10 06:28:05 +11:00
Geoffrey McRae
905fea57f0 [host] nvfbc: fix stride for odd resolutions in 24-bit mode 2023-11-10 06:28:05 +11:00
Geoffrey McRae
3a6afd04d2 [client] egl: use the pitch to calculate the new width for rgb24 2023-11-10 06:28:05 +11:00
Geoffrey McRae
c0e09e13a5 [client] egl: make the bgr_bgra filter generic for 24-bit formats 2023-11-10 06:28:05 +11:00
Geoffrey McRae
3843afa927 [client] egl: fix texture import for RGB_24 2023-11-10 06:28:05 +11:00
Geoffrey McRae
49bdf046fe [client] egl: partially fix RGB_24 support 2023-11-10 06:28:05 +11:00
Geoffrey McRae
8605df8c8d [host] nvfbc: fix damage copy when operating in 24bpp 2023-11-10 06:28:05 +11:00
Geoffrey McRae
d847c2c144 [common] add new frame type string to KVMFR lookup table 2023-11-10 06:28:05 +11:00
Geoffrey McRae
6492c47e1e [client] egl: fix typo 2023-11-10 06:28:05 +11:00
Geoffrey McRae
86e8e99107 [all] add initial support for RGB24-bpp support 2023-11-10 06:28:05 +11:00
Geoffrey McRae
dcde981a17 [client] opengl: fix cursor location when the source is downsampled 2023-11-10 06:28:05 +11:00
Geoffrey McRae
c54a09ca25 [client] opengl: fix row alignment parameter bug 2023-11-10 06:28:05 +11:00
Geoffrey McRae
5bba4dfab5 [host] nvfbc: fix incorrect metadata when resampling is enabled 2023-11-10 06:28:05 +11:00
Geoffrey McRae
3af2cf54d6 [client] egl: remove deprecated BGR members and logic 2023-11-10 06:28:05 +11:00
Geoffrey McRae
4aba15f31c [client] egl: only scale damage rects if it's packed BGR 2023-11-10 06:28:05 +11:00
Geoffrey McRae
a455078e0f [host] dxgi: dont alter the damage rect array when scaling 2023-11-10 06:28:05 +11:00
Geoffrey McRae
f8586fd063 [host] dxgi: fix RGB24 damage rect rounding bug 2023-11-10 06:28:05 +11:00
Geoffrey McRae
ad13928c73 [client] egl: fix bgr filter re-init if DMA mode changes 2023-11-10 06:28:05 +11:00
Geoffrey McRae
f991f994f0 [host] dxgi: rename cpu to tex 2023-11-10 06:28:05 +11:00
Geoffrey McRae
772e0e3b4a [host] dxgi: fix d3d11 invalid memory allocation for backend struct 2023-11-10 06:28:05 +11:00
Geoffrey McRae
fd79bb1333 [host] dxgi: add option to enable RGB24 packing support 2023-11-10 06:28:05 +11:00
Geoffrey McRae
d6519c4486 [host] dxgi: remove unused define 2023-11-10 06:28:05 +11:00
Geoffrey McRae
9fefbae749 [host] dxgi: make dxgi structs private again 2023-11-10 06:28:05 +11:00
Geoffrey McRae
fa561c121e [host] dxgi: move and document dxgi_* exposed functions for backends 2023-11-10 06:28:05 +11:00
Geoffrey McRae
c2e3c37bab [host] dxgi: remove no longer used member for copy backends 2023-11-10 06:28:05 +11:00
Geoffrey McRae
54bd08c3cb [host] dxgi: decouple backends from the DXGI main struct 2023-11-10 06:28:05 +11:00
Geoffrey McRae
eb2796d40b [host] dxgi: move the backend interface into a separate header 2023-11-10 06:28:05 +11:00
Geoffrey McRae
748c9c177e [dxgi] increase the comRef global count 2023-11-10 06:28:05 +11:00
Geoffrey McRae
cc48257aeb [dxgi] d3d12: fix incorrect mapping range 2023-11-10 06:28:05 +11:00
Geoffrey McRae
3838e1f996 [host] dxgi: fix the return status of the downsampler 2023-11-10 06:28:05 +11:00
Geoffrey McRae
881aa9e179 [host] dxgi: fix the d3d12 copy backend 2023-11-10 06:28:05 +11:00
Geoffrey McRae
9a2638bfa0 [host] dxgi: fix unbalanced scope pop 2023-11-10 06:28:05 +11:00
Geoffrey McRae
8d7d5ba8fd [host] dxgi: fix comRef leak in the downsampler 2023-11-10 06:28:05 +11:00
Geoffrey McRae
09b6fee360 [host] dxgi: fix HDR content downsampling 2023-11-10 06:28:05 +11:00
Geoffrey McRae
561c45bcb9 [host] dxgi: fix support for non 24-bit BGR formats 2023-11-10 06:28:05 +11:00
Geoffrey McRae
5f613b09d6 [host] dxgi: implement downsampling to arbitrary sizes 2023-11-10 06:28:05 +11:00
Geoffrey McRae
30c577beeb [host] all: make the downsample rule matching common 2023-11-10 06:28:05 +11:00
Geoffrey McRae
6c7f3c4197 [host] nvfbc: make the downsampleParser available outside of NvFBC 2023-11-10 06:28:05 +11:00
Geoffrey McRae
139e98ac3b [client] OpenGL:fix RGB24 support for non 64-bit aligned pitches 2023-11-10 06:28:05 +11:00
Tudor Brindus
d02e3730b2 [client] EGL: implement damage-aware RGB24 copy 2023-11-10 06:28:05 +11:00
Tudor Brindus
ea5b6b4026 [host] DXGI: implement damage-aware RGB24 copy 2023-11-10 06:28:05 +11:00
Tudor Brindus
6329779893 [host] DXGI: rescale RGB24 texture to 3/4ths the input width
Now that data isn't packed across rows, we can decrease the amount of
texture memory we require.
2023-11-10 06:28:05 +11:00
Tudor Brindus
1da50d220e [client] EGL: stop unpacking data across rows 2023-11-10 06:28:05 +11:00
Tudor Brindus
3106d0e3e2 [host] DXGI: stop packing data across rows
This is a precursor to allowing damage-aware RGB24 copies.
2023-11-10 06:28:05 +11:00
Tudor Brindus
d44fc36fc4 [host] DXGI: stop rescaling RGB24 texture height
For the moment, this just increases texture memory usage, but does not
affect behavior.

In a future commit, I will modify the shaders to not pack data across
rows, in order to enable damage copies.
2023-11-10 06:28:05 +11:00
Tudor Brindus
c29404eea6 [host] DXGI: fixed swapped rows and cols variables
In practice this worked out because `rows = cols`, but this will change
in future commits as I implement RGB24 damage support.
2023-11-10 06:28:05 +11:00
Geoffrey McRae
c665044bfa [client] implement support for RGB24 packed data 2023-11-10 06:28:05 +11:00
Geoffrey McRae
578d98fd22 [host] DXGI: initial implementation of RGB24 support
This commit breaks damage tracking and the dx12 backend and is not in
a state where it should be used by the general public.
2023-11-10 06:28:05 +11:00
Geoffrey McRae
b3879ff1d7 [host] windows: the vertex shader is common to all post-processors 2023-11-10 06:28:05 +11:00
Jonathan Rubenstein
f6b2cec841 [doc] html_unescape: Create html.unescape extension
This new sphinx extension runs html.unescape
(from the Python Standard Library) on source files before they are
rendered, allowing escape sequences like  ' ' for the no-break
space character.

I have also published this extension in my own name under a different
license (the same one Sphinx uses) for others to use:
https://github.com/JJRcop/sphinxcontrib-html_unescape
2023-11-02 06:21:51 +11:00
Jonathan Rubenstein
626f5eb32e [doc] usage: Actually add non-breaking spaces to config file
In 3625207801 I attempted to add
non-breaking spaces to a filepath so it would stay on one line.
Before this I had accidentally deleted my work but found it saved
in my sphinx build cache, so I copied my changes from that cache.

Unfortunately the cached version replaced non-breaking spaces with
real spaces and 3625207801 was made
reverted.

This commit re-adds the non-breaking spaces.
2023-11-02 06:21:51 +11:00
Jonathan Rubenstein
29c797d7b6 [doc] usage: Add Selecting an IVSHMEM device 2023-10-30 14:16:28 +11:00
Jonathan Rubenstein
3625207801 [doc] usage: Add non-breaking spaces to config path 2023-10-30 14:16:28 +11:00
Jonathan Rubenstein
25d6dd3ba2 [doc] usage: Refresh opening paragraph in Host usage 2023-10-30 14:16:28 +11:00
Geoffrey McRae
1e30539fb2 [dxgi] cache the input shader resource view of the src texture 2023-10-29 21:53:48 +11:00
Geoffrey McRae
52410beea7 [host] dxgi: check for correct comRef usage 2023-10-29 20:29:14 +11:00
Geoffrey McRae
c591f7a8ae [common] vector: assert if the vector itemSize <= 0 2023-10-29 20:27:49 +11:00
Geoffrey McRae
21cd380cad [host] dxgi: seperate out and implement a post processor chain 2023-10-29 20:27:17 +11:00
Geoffrey McRae
e225f66cee [host] dxgi: explicitly flush the pipeline to reduce latency 2023-10-27 22:08:33 +11:00
Geoffrey McRae
2206752b66 [host] dxgi: fix d3d12 backend resource leak
The handle is only needed so we can open the resource, once we have
it we can close the handle. We then cache the shared resource for
future reuse if possible.
2023-10-27 21:56:49 +11:00
Geoffrey McRae
0510d06c4b [host] dxgi: fix d3d12 texture sharing when in HDR 2023-10-27 21:22:00 +11:00
Geoffrey McRae
699d95818d [host] dxgi: upate d3d12 backend to use comRef 2023-10-27 21:01:44 +11:00
Geoffrey McRae
fffac35300 [host] dxgi: update d3d11 backend to make use of comRef 2023-10-27 18:44:17 +11:00
Geoffrey McRae
35b0f8edf3 [host] dxgi: allow the HDR texture to be shared with other backends 2023-10-27 18:43:26 +11:00
Geoffrey McRae
544164f637 [host] dxgi: allow the backend to shutdown before freeing comRef globals 2023-10-27 18:42:38 +11:00
Geoffrey McRae
b94166177f [host] dxgi: update to make use of comRef (part 1 of 2) 2023-10-27 17:34:34 +11:00
Geoffrey McRae
69b984aa2c [host] dxgi: add helper to manage COM object memory 2023-10-27 17:33:40 +11:00
Geoffrey McRae
c100df4037 [all] common: debug assert should always abort 2023-10-27 17:32:58 +11:00
Geoffrey McRae
47329ebd89 [host] dxgi: move utility functions into util.c 2023-10-27 11:28:37 +11:00
Geoffrey McRae
5d7469d23e [host] linux: fix build with new HDR changes (untested) 2023-10-27 01:19:46 +11:00
Geoffrey McRae
6625cd733a [client] main: log if the frame format is using PQ or not 2023-10-27 01:16:08 +11:00
Geoffrey McRae
b41840b010 [host] all: tell the client if HDR PQ is in use or not 2023-10-27 01:11:57 +11:00
Geoffrey McRae
2f36aaff5c [client] egl: prepare for DXGI HDR10 support 2023-10-27 01:03:22 +11:00
Geoffrey McRae
200b7b732c [host] dxgi: properly convert HDR16 to HDR10
DXGI doesn't take into account the SDRWhiteLevel that has already been
applied to the monitor when it converts to HDR10 which results in clipping.
This change set implements a HLSL shader to reverse this while at the same
time converting to HDR10.

This is still not perfect but far better then doing nothing.
2023-10-26 22:57:41 +11:00
Geoffrey McRae
eeea24ebfb [client] egl: invalidate the window when HDR settings are changed 2023-10-24 13:46:51 +11:00
Geoffrey McRae
54066094bd [github] workflow: use latest ubuntu for cross compile build 2023-10-22 19:56:21 +11:00
Geoffrey McRae
c5923b9b4d [host] dxgi: obtain HDR color space and monitor information 2023-10-22 17:38:42 +11:00
Geoffrey McRae
bde2eef175 [host] dxgi: fix format for HDR10 when it needs correcting 2023-10-22 04:01:51 +11:00
Geoffrey McRae
e0bdd869d6 [all] fix client build on linux 2023-10-22 04:00:44 +11:00
Geoffrey McRae
ccd0a0bcf9 [host] dxgi: use HDR10 instead of HDR16 to save bandwidth 2023-10-22 03:47:32 +11:00
Geoffrey McRae
742e41c2c3 [host] dxgi: fix HDR damage aware copy 2023-10-22 03:15:12 +11:00
Geoffrey McRae
3ed71a09f4 [common] all: implement strdup directly
Dr.Memory on Windows complains bitterly about invalid heap free as
it doesn't seem to be able to track this function's allocations. As
it's such a trivial function we can just implement it locally.
2023-10-22 02:25:25 +11:00
Geoffrey McRae
12d051d8c0 [host] nvfbc: do not try to init on non NVIDIA hardware 2023-10-22 01:46:57 +11:00
Geoffrey McRae
a6a6b8779a [host] nvfbc: fix use of initialized variable 2023-10-22 01:21:20 +11:00
Geoffrey McRae
ad65561511 [host] app: cleanup local variables during init. 2023-10-21 22:03:22 +11:00
Geoffrey McRae
6b65c7e339 [all] lgmp: update to fix memory leak on shutdown 2023-10-21 22:02:33 +11:00
Geoffrey McRae
646f5b1be8 [host] fix windows compilation with mingw clang 2023-10-21 22:02:02 +11:00
Geoffrey McRae
128a8938c6 [host] nvfbc: remove useless update of member 2023-10-20 22:12:42 +11:00
Geoffrey McRae
2e515657dd [all] update/add license headers 2023-10-20 15:36:34 +11:00
Geoffrey McRae
1cf8e8c846 [doc] add luminance to words 2023-10-20 15:34:35 +11:00
Geoffrey McRae
df5c648377 [client] egl: remove unit qualifier from label 2023-10-20 15:30:36 +11:00
Geoffrey McRae
78df2073ff [client] egl: make it possible to configure HDR to SDR mapping 2023-10-20 15:26:27 +11:00
Geoffrey McRae
844a37a276 [all] update LGMP to fix invalid index access bug 2023-10-20 14:21:11 +11:00
Geoffrey McRae
e658c2e0a2 [client] x11: change to a more visible "dot" cursor
This change alters the small square dot cursor to a more visible 16x16
cursor for X11. A new option `spice:largeDotCursor` can be set to use an
alternative 32x32 cursor for the vision impaired.
2023-09-13 21:54:31 +10:00
Geoffrey McRae
b2ec60d2dc [client/host] common: fix trim value bug reading the wrong variable 2023-09-13 21:54:31 +10:00
Zenithal
e6aa2b85a9 [module] AMD SEV support 2023-09-13 15:12:40 +10:00
Geoffrey McRae
a3045e0b4a [client] main: don't request activation just because we re-connected 2023-09-13 14:08:18 +10:00
Geoffrey McRae
9cadb64942 [client] main: make activation requests optional 2023-09-13 14:07:42 +10:00
Geoffrey McRae
82607a7d6f [client] x11: read the i3 IPC response 2023-09-12 02:03:24 +10:00
Geoffrey McRae
8d90c9c2a5 [doc] add new words to words.txt 2023-09-12 01:27:34 +10:00
Geoffrey McRae
24d4fce17c [client] x11: add support for i3 global full screen toggle
This commit adds an interface to the X11 display server code to support
various window manage specific features, such as in this case, the i3
global full screen toggle.

This feature specifically uses the i3 IPC to cause looking glass to go
full screen across all monitors if the new option `i3:globalFullScreen`
is enabled.
2023-09-12 01:19:06 +10:00
Geoffrey McRae
8dba4b6c0b [client] x11: fix cleanup if XIQueryVersion fails 2023-09-11 23:41:52 +10:00
Geoffrey McRae
193977895b [client] add new option input:captureOnFocus
This option allows the client to automatically enter capture mode if the
window is focused.

Closes #1088
2023-09-11 21:02:32 +10:00
Jonathan Rubenstein
219c73edbe [doc] faq.rst: Reword libdecor package installation
Also change package name to Debian
package libdecor-0-dev
2023-07-25 10:15:28 +10:00
Jonathan Rubenstein
6522920ea1 [doc] faq.rst: Update libdecor source link
Source code moved from https://gitlab.gnome.org/jadahl/libdecor
to https://gitlab.freedesktop.org/libdecor/libdecor
2023-07-25 10:15:28 +10:00
esi
e32b292cc1 [module] Fix build on Linux 6.4 (fixes #1075) 2023-06-30 07:29:15 +10:00
Netboy3
53525847fd [common] options: Fix regression in option parsing logic 2023-05-03 18:20:01 +10:00
Geoffrey McRae
9d66a68403 [common] options: fix build on windows (no strndup) 2023-05-02 12:32:59 +10:00
Geoffrey McRae
07bcc54732 [common] options: trim whitespace from option values
This closes #1071
2023-05-02 12:27:17 +10:00
Geoffrey McRae
dab5618a6d [host] linux: fix compilation 2023-04-26 16:31:02 +10:00
Geoffrey McRae
ad43969c1a [client] egl: add support to map HDR to SDR 2023-04-26 16:26:54 +10:00
Geoffrey McRae
99333a03c1 [host] nvfbc: fix failure to store last hdr state 2023-04-26 15:58:22 +10:00
Geoffrey McRae
45318aa653 [host] nvfbc: bump the format version when HDR status changes 2023-04-26 15:55:26 +10:00
Geoffrey McRae
f84165ac66 [host] app: report to the client if the frame is actually HDR 2023-04-26 15:48:01 +10:00
Geoffrey McRae
e4a8424fad [host] nvfbc: fix ARGB10 support
There is no performance penalty to using ARGB10 as it's still a 32-bit copy per
pixel and the nvidia driver internally handles any conversions required to make
this work for both SDR and HDR.
2023-04-19 19:52:30 +10:00
Geoffrey McRae
880d8042a4 [client] egl: fix support for deep color modes (30bpp) 2023-04-19 18:02:14 +10:00
Geoffrey McRae
a629d24dc3 [client] egl: fix fourcc for RGBA10 dmabuf 2023-04-19 17:30:40 +10:00
MakiseKurisu
7c1bb13d70 [all] add MakiseKurisu to AUTHORS 2023-04-16 19:50:35 +10:00
MakiseKurisu
9d5c543a53 [module] add logging for kvmfr_module_init 2023-04-16 19:50:35 +10:00
MakiseKurisu
063a859de1 [module] add logging for kvmfr_pci_probe 2023-04-16 19:50:35 +10:00
Geoffrey McRae
4f4cf2be7d [client] audio: provide option to prevent volume level sync 2023-04-16 19:10:35 +10:00
Geoffrey McRae
9759b5aa8f [idd] the cursor pos is only valid if it's visible 2023-04-14 21:40:21 +10:00
Geoffrey McRae
bbd0c7a99b [idd] implement cursor shape & position transmission 2023-04-14 20:40:00 +10:00
Geoffrey McRae
c11748a76f [idd] remove unused member variable 2023-04-14 14:10:19 +10:00
Geoffrey McRae
d6b26b0eb1 [idd] resend the last captured frame if a new client connects 2023-04-14 14:08:09 +10:00
Geoffrey McRae
fd0cc6aa10 [idd] consistency: change t to st 2023-04-14 14:08:03 +10:00
Geoffrey McRae
80b9bda59d [idd] keep the textures mapped until overwrite for future re-use 2023-04-14 13:26:08 +10:00
Geoffrey McRae
0c176acf94 [idd] updated to a VS2022 project with Windows 10 support 2023-04-14 12:14:17 +10:00
Geoffrey McRae
0c3dce3ca6 [idd] implemented frame feed from the guest (very hacky)
This is NOT READY for general consumption, if you decide to make
use of this driver, DO NOT ASK FOR SUPPORT.
2023-04-11 16:55:58 +10:00
Geoffrey McRae
3c85957b99 [idd] implemented core shared memory functionallity and LGMP setup 2023-04-11 16:53:57 +10:00
Geoffrey McRae
77ddcfe489 [idd] implement CIVSHMEM and open it 2023-04-11 16:53:57 +10:00
Geoffrey McRae
d228ef135e [idd] target a specific version of windows 2023-04-11 16:53:57 +10:00
Geoffrey McRae
0afcf2c2ce [idd] add LGMP to the project 2023-04-11 16:53:57 +10:00
Geoffrey McRae
75da66a090 [idd] initial indirect driver with Looking Glass monitor 2023-04-11 16:53:57 +10:00
Geoffrey McRae
11676d3d56 [common] windows: fix invalid free of stack allocated memory 2023-04-11 16:51:25 +10:00
Geoffrey McRae
b13682a9ef [lgmp] update library to fix issues with MSVC builds 2023-04-11 16:51:02 +10:00
Geoffrey McRae
642634293d [lgmp] update to fix compilation under MSVC 2023-04-10 10:24:53 +10:00
Geoffrey McRae
01f9c2bfb5 [lgmp] update to fix alignment with MSVC compiled code 2023-04-10 10:21:39 +10:00
Geoffrey McRae
9385b2de7a [submodule] update LGMP to the latest version for incoming Idd support 2023-04-10 03:07:07 +10:00
Jonathan Rubenstein
d2f7667fae [github] CODEOWERS: Fix typo stopping JJRcop owning /doc/
Made an embarassing typo
2023-04-09 09:43:19 +10:00
Jonathan Rubenstein
cfef966603 [github] build: Use debian package for sphinxcontrib-spelling 2023-04-05 08:13:54 +10:00
Jonathan Rubenstein
4f09d5b771 [doc] troubleshooting: Rewrite missing desktop 2023-04-04 23:31:41 +10:00
Geoffrey McRae
b7b302334c [client] main: remove debug true from if statement 2023-04-02 20:14:16 +10:00
Geoffrey McRae
28e74a73a4 [client] main: detect and warn on sub-optimal guest CPU configuration 2023-04-02 20:13:14 +10:00
Geoffrey McRae
996e1b2f7a [client] overlay: fix race on startup that caused a segfault
Fixes #1065
2023-03-30 14:59:37 +11:00
Geoffrey McRae
0ee5751b3a [client] egl: fix buffer overflow 2023-03-30 14:16:51 +11:00
Geoffrey McRae
e067db7bb4 [doc] fix typos and correct 1440p resolution.
Closes #1064
Closes #1061
2023-03-19 12:57:16 +11:00
Geoffrey McRae
b4b4a37b2b [client] egl: switch to using GL_TEXTURE_EXTERNAL_OES for DMABUF
According to Erik @ NVidia the open source NVidia driver will not
create a EGLImage from a DMABUF if the target is not
GL_TEXTURE_EXTERNAL_OES. This change set converts the dmabuf texture
from GL_TEXTURE_2D to GL_TEXTURE_EXTERNAL_OES and at runtime performs a
global search & replace on fragment shaders as needed to remain
compatible, replacing `sampler2D` with `samplerExternalOES`.

Ref: https://github.com/NVIDIA/open-gpu-kernel-modules/discussions/243#discussioncomment-3283415
2023-03-09 09:20:01 +11:00
Geoffrey McRae
bbc9204bfe [client] egl: ensure the preprocessed files have a null terminator 2023-03-09 09:15:39 +11:00
Geoffrey McRae
894b8b0c22 [client] x11: generate synthetic EnterNotify event on cursor leave
If the cursor was grabbed the window the cursor moves over when it is
ungrabbed will recieve an EnterNotify event with the mode of
NotifyUngrab, unfortunatly some window manages such as i3 will ignore
this message and as such focus follows mouse will not function
correctly. This patch injects a normal EnterNotify to work around this
issue.
2023-03-05 16:42:47 +11:00
Geoffrey McRae
91b0cba145 [client] egl: switch from mediump to highp
This fixes a rounding issue on certain hardware (NVidia) which actually
implement mediump as half precision (16-bit) float. It's safe to assume
`highp` is available as if the GPU does not support it, then the shader
compiler will try to find a lower precision that is supported by the GPU
2023-03-05 14:10:21 +11:00
Geoffrey McRae
2f48798db9 [client] wayland: check for failure of wl_display_connect 2023-02-28 23:38:44 +11:00
Geoffrey McRae
254b370bbf [client] audio/pipewire: fix compilation under clang 2023-01-24 13:46:22 +11:00
Geoffrey McRae
86efc47505 [client] audio/pipewire: PW_KEY_TARGET_OBJECT only exists as of 0.3.44 2023-01-24 13:43:17 +11:00
Geoffrey McRae
b559d6b9bc [client] audio/pipewire: add options to set the default out/rec devices 2023-01-24 13:35:25 +11:00
Geoffrey McRae
48cd0c3789 [client] audio: add missing earlyInit call for audio devs 2023-01-24 13:35:18 +11:00
Geoffrey McRae
6f8e6f9a19 [client] x11: catch and print details of X11 errors with a backtrace 2023-01-05 17:33:01 +11:00
Geoffrey McRae
188f25c6bf [host] nvfbc: increase retry timeout to 1 second 2022-12-09 08:00:03 +11:00
Geoffrey McRae
8619f787b9 [host] nvfbc: retry on failure to init
@quantum has observed nvfbc under rare circumstances fail to initialize,
this adds a retry to the init with a short delay to hopefully recover
from this situation.
2022-12-08 21:24:11 +11:00
Quantum
60ac03ebaf [client] wayland: implement window size setting for xdg-shell
This should allow win:autoResize to work on Wayland when the compositor
supports such an operation.
2022-12-08 21:08:33 +11:00
Quantum
e1ebde3cd2 [host] windows: log to stderr that logs will continue in file
This prevents users from posting the stderr as if it's the only output.
2022-12-08 21:08:07 +11:00
Quantum
f519904c38 [host] app: clarify that config file not found is not fatal
This prevents users from thinking this is the problem they are facing.
2022-12-08 21:08:07 +11:00
Geoffrey McRae
fa6f1abaac [obs] fix compatibility with updated LGMP build 2022-11-08 00:00:39 +11:00
Geoffrey McRae
875242fe15 [host] app: improve throttleFPS logic 2022-11-07 22:56:20 +11:00
Geoffrey McRae
20b5957999 [client] update LGMP to fix buffer overflow bug 2022-11-07 21:57:10 +11:00
317 changed files with 9571 additions and 2378 deletions

2
.github/CODEOWNERS vendored
View File

@@ -1,4 +1,4 @@
# Jonathan Rubenstein (JJRcop)
# - Primary documentation manager. Does not require direct approval for every
# - change, but should be consulted for large additions and changes.
docs/ jrubcop@gmail.com
/doc/ jrubcop@gmail.com

View File

@@ -97,7 +97,7 @@ jobs:
make -j$(nproc)
host-windows-cross:
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
@@ -183,8 +183,8 @@ jobs:
sudo apt-get update
- name: Install docs dependencies
run: |
sudo apt-get install python3-sphinx python3-sphinx-rtd-theme
sudo pip3 install sphinxcontrib-spelling
sudo apt-get install python3-sphinx python3-sphinx-rtd-theme \
python3-sphinxcontrib.spelling
- name: Build docs
run: |
cd doc

5
.gitignore vendored
View File

@@ -10,3 +10,8 @@ module/modules.order
*/build
__pycache__
*.py[co]
*/.vs
idd/Debug
idd/x64
idd/LGIdd/x64
idd/LGIdd/Debug

View File

@@ -65,3 +65,5 @@ Leonard Fricke <leonard.fricke98@gmail.com> (Leo1998)
David Meier <meier_david_91@hotmail.com> (Kenny.ch)
Daniel Cordero <looking-glass@0xdc.io> (0xdc)
esi <git@esibun.net> (esibun)
MakiseKurisu <saberconer@gmail.com> (MakiseKurisu)
Zenithal <i@zenithal.me> (ZenithalHourlyRate)

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.0)
cmake_minimum_required(VERSION 3.5)
project(looking-glass-client C CXX)
get_filename_component(PROJECT_TOP "${PROJECT_SOURCE_DIR}/.." ABSOLUTE)
@@ -45,12 +45,6 @@ add_feature_info(ENABLE_UBSAN ENABLE_UBSAN "UndefinedBehaviorSanitizer support."
option(ENABLE_X11 "Build with X11 support" ON)
add_feature_info(ENABLE_X11 ENABLE_X11 "X11 support.")
option(ENABLE_WAYLAND "Build with Wayland support" ON)
add_feature_info(ENABLE_WAYLAND ENABLE_WAYLAND "Wayland support.")
option(ENABLE_LIBDECOR "Build with libdecor support" OFF)
add_feature_info(ENABLE_LIBDECOR ENABLE_LIBDECOR "libdecor support.")
option(ENABLE_PIPEWIRE "Build with PipeWire audio output support" ON)
add_feature_info(ENABLE_PIPEWIRE ENABLE_PIPEWIRE "PipeWire audio support.")

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.0)
cmake_minimum_required(VERSION 3.5)
project(audiodevs LANGUAGES C)
set(AUDIODEV_H "${CMAKE_BINARY_DIR}/include/dynamic/audiodev.h")

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.0)
cmake_minimum_required(VERSION 3.5)
project(audiodev_PipeWire LANGUAGES C)
find_package(PkgConfig)

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -28,6 +28,7 @@
#include "common/debug.h"
#include "common/stringutils.h"
#include "common/util.h"
#include "common/option.h"
typedef enum
{
@@ -129,6 +130,29 @@ static void pipewire_onPlaybackDrained(void * userdata)
pw_thread_loop_unlock(pw.thread);
}
static struct Option pipewire_options[] =
{
{
.module = "pipewire",
.name = "outDevice",
.description = "The default playback device to use",
.type = OPTION_TYPE_STRING
},
{
.module = "pipewire",
.name = "recDevice",
.description = "The default record device to use",
.type = OPTION_TYPE_STRING
},
{0}
};
static void pipewire_earlyInit(void)
{
option_register(pipewire_options);
}
static bool pipewire_init(void)
{
pw_init(NULL, NULL);
@@ -221,9 +245,8 @@ static void pipewire_playbackSetup(int channels, int sampleRate,
pw.playback.pullFn = pullFn;
pw_thread_loop_lock(pw.thread);
pw.playback.stream = pw_stream_new_simple(
pw.loop,
"Looking Glass",
struct pw_properties * props =
pw_properties_new(
PW_KEY_NODE_NAME , "Looking Glass",
PW_KEY_MEDIA_TYPE , "Audio",
@@ -231,7 +254,22 @@ static void pipewire_playbackSetup(int channels, int sampleRate,
PW_KEY_MEDIA_ROLE , "Music",
PW_KEY_NODE_LATENCY , requestedNodeLatency,
NULL
),
);
const char * device = option_get_string("pipewire", "outDevice");
if (device)
{
#ifdef PW_KEY_TARGET_OBJECT
pw_properties_set(props, PW_KEY_TARGET_OBJECT, device);
#else
pw_properties_set(props, PW_KEY_NODE_TARGET, device);
#endif
}
pw.playback.stream = pw_stream_new_simple(
pw.loop,
"Looking Glass",
props,
&events,
NULL
);
@@ -449,17 +487,30 @@ static void pipewire_recordStart(int channels, int sampleRate,
pw.record.stride = sizeof(uint16_t) * channels;
pw.record.pushFn = pushFn;
pw_thread_loop_lock(pw.thread);
pw.record.stream = pw_stream_new_simple(
pw.loop,
"Looking Glass",
struct pw_properties * props =
pw_properties_new(
PW_KEY_NODE_NAME , "Looking Glass",
PW_KEY_MEDIA_TYPE , "Audio",
PW_KEY_MEDIA_CATEGORY, "Capture",
PW_KEY_MEDIA_ROLE , "Music",
NULL
),
);
const char * device = option_get_string("pipewire", "recDevice");
if (device)
{
#ifdef PW_KEY_TARGET_OBJECT
pw_properties_set(props, PW_KEY_TARGET_OBJECT, device);
#else
pw_properties_set(props, PW_KEY_NODE_TARGET, device);
#endif
}
pw_thread_loop_lock(pw.thread);
pw.record.stream = pw_stream_new_simple(
pw.loop,
"Looking Glass",
props,
&events,
NULL
);
@@ -543,9 +594,10 @@ static void pipewire_free(void)
struct LG_AudioDevOps LGAD_PipeWire =
{
.name = "PipeWire",
.init = pipewire_init,
.free = pipewire_free,
.name = "PipeWire",
.earlyInit = pipewire_earlyInit,
.init = pipewire_init,
.free = pipewire_free,
.playback =
{
.setup = pipewire_playbackSetup,

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.0)
cmake_minimum_required(VERSION 3.5)
project(audiodev_PulseAudio LANGUAGES C)
find_package(PkgConfig)

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.0)
cmake_minimum_required(VERSION 3.5)
project(displayservers LANGUAGES C)
set(DISPLAYSERVER_H "${CMAKE_BINARY_DIR}/include/dynamic/displayservers.h")
@@ -18,6 +18,9 @@ function(add_displayserver name)
add_subdirectory(${name})
endfunction()
option(ENABLE_WAYLAND "Build with Wayland support" ON)
add_feature_info(ENABLE_WAYLAND ENABLE_WAYLAND "Wayland support.")
# Add/remove displayservers here!
if (ENABLE_WAYLAND)
add_displayserver(Wayland)

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.0)
cmake_minimum_required(VERSION 3.5)
project(displayserver_Wayland LANGUAGES C)
find_package(PkgConfig)
@@ -8,19 +8,7 @@ pkg_check_modules(DISPLAYSERVER_Wayland REQUIRED IMPORTED_TARGET
xkbcommon
)
set(DISPLAYSERVER_Wayland_OPT_PKGCONFIG_LIBRARIES "")
set(displayserver_Wayland_SHELL_SRC "")
if (ENABLE_LIBDECOR)
pkg_check_modules(DISPLAYSERVER_Wayland_LIBDECOR REQUIRED IMPORTED_TARGET
libdecor-0
)
list(APPEND DISPLAYSERVER_Wayland_OPT_PKGCONFIG_LIBRARIES PkgConfig::DISPLAYSERVER_Wayland_LIBDECOR)
list(APPEND displayserver_Wayland_SHELL_SRC shell_libdecor.c)
add_compile_definitions(ENABLE_LIBDECOR)
else()
list(APPEND displayserver_Wayland_SHELL_SRC shell_xdg.c)
endif()
find_program(WAYLAND_SCANNER_EXECUTABLE NAMES wayland-scanner)
add_library(displayserver_Wayland STATIC
activation.c
@@ -36,66 +24,19 @@ add_library(displayserver_Wayland STATIC
registry.c
wayland.c
window.c
${displayserver_Wayland_SHELL_SRC}
)
add_subdirectory(protocol)
add_subdirectory(desktops)
target_link_libraries(displayserver_Wayland
PkgConfig::DISPLAYSERVER_Wayland
${DISPLAYSERVER_Wayland_OPT_PKGCONFIG_LIBRARIES}
lg_common
wayland_protocol
wayland_desktops
)
target_include_directories(displayserver_Wayland
PRIVATE
src
.
)
find_program(WAYLAND_SCANNER_EXECUTABLE NAMES wayland-scanner)
macro(wayland_generate protocol_file output_file)
add_custom_command(OUTPUT "${output_file}.h"
COMMAND "${WAYLAND_SCANNER_EXECUTABLE}" client-header "${protocol_file}" "${output_file}.h"
DEPENDS "${protocol_file}"
VERBATIM)
add_custom_command(OUTPUT "${output_file}.c"
COMMAND "${WAYLAND_SCANNER_EXECUTABLE}" private-code "${protocol_file}" "${output_file}.c"
DEPENDS "${protocol_file}"
VERBATIM)
target_sources(displayserver_Wayland PRIVATE "${output_file}.h" "${output_file}.c")
endmacro()
set(WAYLAND_PROTOCOLS_BASE "${PROJECT_TOP}/repos/wayland-protocols")
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/wayland")
include_directories("${CMAKE_BINARY_DIR}/wayland")
wayland_generate(
"${WAYLAND_PROTOCOLS_BASE}/stable/xdg-shell/xdg-shell.xml"
"${CMAKE_BINARY_DIR}/wayland/wayland-xdg-shell-client-protocol")
wayland_generate(
"${WAYLAND_PROTOCOLS_BASE}/stable/presentation-time/presentation-time.xml"
"${CMAKE_BINARY_DIR}/wayland/wayland-presentation-time-client-protocol")
wayland_generate(
"${WAYLAND_PROTOCOLS_BASE}/stable/viewporter/viewporter.xml"
"${CMAKE_BINARY_DIR}/wayland/wayland-viewporter-client-protocol")
wayland_generate(
"${WAYLAND_PROTOCOLS_BASE}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml"
"${CMAKE_BINARY_DIR}/wayland/wayland-xdg-decoration-unstable-v1-client-protocol")
wayland_generate(
"${WAYLAND_PROTOCOLS_BASE}/unstable/relative-pointer/relative-pointer-unstable-v1.xml"
"${CMAKE_BINARY_DIR}/wayland/wayland-relative-pointer-unstable-v1-client-protocol")
wayland_generate(
"${WAYLAND_PROTOCOLS_BASE}/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml"
"${CMAKE_BINARY_DIR}/wayland/wayland-pointer-constraints-unstable-v1-client-protocol")
wayland_generate(
"${WAYLAND_PROTOCOLS_BASE}/unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml"
"${CMAKE_BINARY_DIR}/wayland/wayland-keyboard-shortcuts-inhibit-unstable-v1-client-protocol")
wayland_generate(
"${WAYLAND_PROTOCOLS_BASE}/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml"
"${CMAKE_BINARY_DIR}/wayland/wayland-idle-inhibit-unstable-v1-client-protocol")
wayland_generate(
"${WAYLAND_PROTOCOLS_BASE}/unstable/xdg-output/xdg-output-unstable-v1.xml"
"${CMAKE_BINARY_DIR}/wayland/wayland-xdg-output-unstable-v1-client-protocol")
wayland_generate(
"${WAYLAND_PROTOCOLS_BASE}/staging/xdg-activation/xdg-activation-v1.xml"
"${CMAKE_BINARY_DIR}/wayland/wayland-xdg-activation-v1-client-protocol")

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it

View File

@@ -0,0 +1,58 @@
cmake_minimum_required(VERSION 3.5)
project(wayland_desktops LANGUAGES C)
set(DESKTOP_H "${CMAKE_BINARY_DIR}/include/dynamic/wayland_desktops.h")
set(DESKTOP_C "${CMAKE_BINARY_DIR}/src/wayland_desktops.c")
file(WRITE ${DESKTOP_H} "#include \"interface/desktop.h\"\n\n")
file(APPEND ${DESKTOP_H} "extern struct WL_DesktopOps * WL_Desktops[];\n\n")
file(WRITE ${DESKTOP_C} "#include \"interface/desktop.h\"\n\n")
file(APPEND ${DESKTOP_C} "#include <stddef.h>\n\n")
set(DESKTOPS "_")
set(DESKTOPS_LINK "_")
function(add_desktop name)
set(DESKTOPS "${DESKTOPS};${name}" PARENT_SCOPE)
set(DESKTOPS_LINK "${DESKTOPS_LINK};wayland_desktop_${name}" PARENT_SCOPE)
add_subdirectory(${name})
endfunction()
# Add/remove desktops here!
# the first entry here is the default
add_desktop(xdg)
pkg_check_modules(LIBDECOR IMPORTED_TARGET libdecor-0)
if(LIBDECOR_FOUND)
option(ENABLE_LIBDECOR "Build with libdecor support" ON)
else()
option(ENABLE_LIBDECOR "Build with libdecor support" OFF)
endif()
add_feature_info(ENABLE_LIBDECOR ENABLE_LIBDECOR "libdecor support.")
if (ENABLE_LIBDECOR)
add_desktop(libdecor)
endif()
list(REMOVE_AT DESKTOPS 0)
list(REMOVE_AT DESKTOPS_LINK 0)
list(LENGTH DESKTOPS DESKTOP_COUNT)
file(APPEND ${DESKTOP_H} "#define WL_DESKTOP_COUNT ${DESKTOP_COUNT}\n")
foreach(desktop ${DESKTOPS})
file(APPEND ${DESKTOP_C} "extern struct WL_DesktopOps WLD_${desktop};\n")
endforeach()
file(APPEND ${DESKTOP_C} "\nconst struct WL_DesktopOps * WL_Desktops[] =\n{\n")
foreach(desktop ${DESKTOPS})
file(APPEND ${DESKTOP_C} " &WLD_${desktop},\n")
endforeach()
file(APPEND ${DESKTOP_C} " NULL\n};")
add_library(wayland_desktops STATIC ${DESKTOP_C})
target_link_libraries(wayland_desktops ${DESKTOPS_LINK})
target_include_directories(wayland_desktops
PRIVATE
../
)

View File

@@ -0,0 +1,16 @@
cmake_minimum_required(VERSION 3.5)
project(wayland_desktop_libdecor LANGUAGES C)
add_library(wayland_desktop_libdecor STATIC
libdecor.c
)
target_link_libraries(wayland_desktop_libdecor
lg_common
wayland_protocol
PkgConfig::LIBDECOR
)
include_directories(
"../../"
)

View File

@@ -0,0 +1,269 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 59
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "interface/desktop.h"
#include "wayland-xdg-shell-client-protocol.h"
#include "wayland.h"
#include <errno.h>
#include <stdbool.h>
#include <string.h>
#include <sys/epoll.h>
#include <libdecor.h>
#include <wayland-client.h>
#include "app.h"
#include "common/debug.h"
// Maximum number of fds we can process at once in waylandWait
#define MAX_EPOLL_EVENTS 10
typedef struct LibDecorState
{
bool configured;
struct libdecor * libdecor;
struct libdecor_frame * libdecorFrame;
int32_t width, height;
bool needsResize;
bool fullscreen;
uint32_t resizeSerial;
}
LibDecorState;
static LibDecorState state = {0};
struct libdecor_configuration
{
uint32_t serial;
bool has_window_state;
enum libdecor_window_state window_state;
bool has_size;
int window_width;
int window_height;
};
static void libdecorHandleError(struct libdecor * context, enum libdecor_error error,
const char *message)
{
DEBUG_ERROR("Got libdecor error (%d): %s", error, message);
}
static void libdecorFrameConfigure(struct libdecor_frame * frame,
struct libdecor_configuration * configuration, void * opaque)
{
if (!state.configured)
{
xdg_surface_ack_configure(libdecor_frame_get_xdg_surface(frame), configuration->serial);
state.configured = true;
return;
}
int width, height;
if (libdecor_configuration_get_content_size(configuration, frame, &width, &height))
{
state.width = width;
state.height = height;
struct libdecor_state * s = libdecor_state_new(width, height);
libdecor_frame_commit(state.libdecorFrame, s, NULL);
libdecor_state_free(s);
}
enum libdecor_window_state windowState;
if (libdecor_configuration_get_window_state(configuration, &windowState))
state.fullscreen = windowState & LIBDECOR_WINDOW_STATE_FULLSCREEN;
state.resizeSerial = configuration->serial;
waylandNeedsResize();
}
static void libdecorFrameClose(struct libdecor_frame * frame, void * opaque)
{
app_handleCloseEvent();
}
static void libdecorFrameCommit(struct libdecor_frame * frame, void * opaque)
{
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
static struct libdecor_interface libdecorListener =
{
libdecorHandleError,
};
static struct libdecor_frame_interface libdecorFrameListener =
{
libdecorFrameConfigure,
libdecorFrameClose,
libdecorFrameCommit,
};
#pragma GCC diagnostic pop
static void libdecorCallback(uint32_t events, void * opaque)
{
libdecor_dispatch(state.libdecor, 0);
}
static bool libdecor_shellInit(
struct wl_display * display, struct wl_surface * surface,
const char * title, bool fullscreen,
bool maximize, bool borderless, bool resizable)
{
state.libdecor = libdecor_new(display, &libdecorListener);
state.libdecorFrame = libdecor_decorate(state.libdecor, surface,
&libdecorFrameListener, NULL);
libdecor_frame_set_app_id(state.libdecorFrame, "looking-glass-client");
libdecor_frame_set_title(state.libdecorFrame, title);
libdecor_frame_map(state.libdecorFrame);
if (resizable)
libdecor_frame_set_capabilities(state.libdecorFrame,
LIBDECOR_ACTION_RESIZE);
else
libdecor_frame_unset_capabilities(state.libdecorFrame,
LIBDECOR_ACTION_RESIZE);
while (!state.configured)
libdecor_dispatch(state.libdecor, 0);
if (!waylandPollRegister(libdecor_get_fd(state.libdecor),
libdecorCallback, NULL, EPOLLIN))
{
DEBUG_ERROR("Failed register display to epoll: %s", strerror(errno));
return false;
}
return true;
}
static void libdecor_shellAckConfigureIfNeeded(void)
{
if (state.resizeSerial)
{
xdg_surface_ack_configure(
libdecor_frame_get_xdg_surface(state.libdecorFrame), state.resizeSerial);
state.resizeSerial = 0;
}
}
static void libdecor_setFullscreen(bool fs)
{
if (fs)
libdecor_frame_set_fullscreen(state.libdecorFrame, NULL);
else
libdecor_frame_unset_fullscreen(state.libdecorFrame);
libdecor_frame_set_visibility(state.libdecorFrame, !fs);
}
static bool libdecor_getFullscreen(void)
{
return state.fullscreen;
}
static void libdecor_minimize(void)
{
libdecor_frame_set_minimized(state.libdecorFrame);
}
static void libdecor_shellResize(int w, int h)
{
if (!libdecor_frame_is_floating(state.libdecorFrame))
return;
state.width = w;
state.height = h;
struct libdecor_state * s = libdecor_state_new(w, h);
libdecor_frame_commit(state.libdecorFrame, s, NULL);
libdecor_state_free(s);
waylandNeedsResize();
}
static void libdecor_setSize(int w, int h)
{
state.width = w;
state.height = h;
}
static void libdecor_getSize(int * w, int * h)
{
*w = state.width;
*h = state.height;
}
static bool libdecor_registryGlobalHandler(void * data,
struct wl_registry * registry, uint32_t name, const char * interface,
uint32_t version)
{
return false;
}
bool libdecor_pollInit(struct wl_display * display)
{
return true;
}
void libdecor_pollWait(struct wl_display * display, int epollFd,
unsigned int time)
{
libdecor_dispatch(state.libdecor, 0);
struct epoll_event events[MAX_EPOLL_EVENTS];
int count;
if ((count = epoll_wait(epollFd, events, MAX_EPOLL_EVENTS, time)) < 0)
{
if (errno != EINTR)
DEBUG_INFO("epoll failed: %s", strerror(errno));
return;
}
for (int i = 0; i < count; ++i)
{
struct WaylandPoll * poll = events[i].data.ptr;
if (!poll->removed)
poll->callback(events[i].events, poll->opaque);
}
}
WL_DesktopOps WLD_libdecor =
{
.name = "libdecor",
.compositor = "gnome-shell",
.shellInit = libdecor_shellInit,
.shellAckConfigureIfNeeded = libdecor_shellAckConfigureIfNeeded,
.setFullscreen = libdecor_setFullscreen,
.getFullscreen = libdecor_getFullscreen,
.minimize = libdecor_minimize,
.shellResize = libdecor_shellResize,
.setSize = libdecor_setSize,
.getSize = libdecor_getSize,
.registryGlobalHandler = libdecor_registryGlobalHandler,
.pollInit = libdecor_pollInit,
.pollWait = libdecor_pollWait
};

View File

@@ -0,0 +1,15 @@
cmake_minimum_required(VERSION 3.5)
project(wayland_desktop_xdg LANGUAGES C)
add_library(wayland_desktop_xdg STATIC
xdg.c
)
target_link_libraries(wayland_desktop_xdg
lg_common
wayland_protocol
)
include_directories(
"../../"
)

View File

@@ -0,0 +1,314 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 59
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "wayland.h"
#include "wayland-xdg-shell-client-protocol.h"
#include "wayland-xdg-decoration-unstable-v1-client-protocol.h"
#include <stdbool.h>
#include <string.h>
#include <sys/epoll.h>
#include <errno.h>
#include <wayland-client.h>
#include "app.h"
#include "common/debug.h"
// Maximum number of fds we can process at once in waylandWait
#define MAX_EPOLL_EVENTS 10
typedef struct XDGState
{
bool configured;
struct xdg_wm_base * wmBase;
struct xdg_surface * surface;
struct xdg_toplevel * toplevel;
struct zxdg_decoration_manager_v1 * decorationManager;
struct zxdg_toplevel_decoration_v1 * toplevelDecoration;
int32_t width, height;
uint32_t resizeSerial;
bool fullscreen;
bool floating;
int displayFd;
}
XDGState;
static XDGState state = {0};
// XDG WM base listeners.
static void xdgWmBasePing(void * data, struct xdg_wm_base * xdgWmBase, uint32_t serial)
{
xdg_wm_base_pong(xdgWmBase, serial);
}
static const struct xdg_wm_base_listener xdgWmBaseListener = {
.ping = xdgWmBasePing,
};
// XDG Surface listeners.
static void xdgSurfaceConfigure(void * data, struct xdg_surface * xdgSurface,
uint32_t serial)
{
if (state.configured)
{
state.resizeSerial = serial;
waylandNeedsResize();
}
else
{
xdg_surface_ack_configure(xdgSurface, serial);
state.configured = true;
}
}
static const struct xdg_surface_listener xdgSurfaceListener = {
.configure = xdgSurfaceConfigure,
};
// XDG Toplevel listeners.
static void xdgToplevelConfigure(void * data, struct xdg_toplevel * xdgToplevel,
int32_t width, int32_t height, struct wl_array * states)
{
state.width = width;
state.height = height;
state.fullscreen = false;
state.floating = true;
enum xdg_toplevel_state * s;
wl_array_for_each(s, states)
{
switch (*s)
{
case XDG_TOPLEVEL_STATE_FULLSCREEN:
state.fullscreen = true;
// fallthrough
case XDG_TOPLEVEL_STATE_MAXIMIZED:
case XDG_TOPLEVEL_STATE_TILED_LEFT:
case XDG_TOPLEVEL_STATE_TILED_RIGHT:
case XDG_TOPLEVEL_STATE_TILED_TOP:
case XDG_TOPLEVEL_STATE_TILED_BOTTOM:
state.floating = false;
break;
default:
break;
}
}
}
static void xdgToplevelClose(void * data, struct xdg_toplevel * xdgToplevel)
{
app_handleCloseEvent();
}
static const struct xdg_toplevel_listener xdgToplevelListener = {
.configure = xdgToplevelConfigure,
.close = xdgToplevelClose,
};
bool xdg_shellInit(struct wl_display * display, struct wl_surface * surface,
const char * title, bool fullscreen, bool maximize, bool borderless,
bool resizable)
{
if (!state.wmBase)
{
DEBUG_ERROR("Compositor missing xdg_wm_base, will not proceed");
return false;
}
xdg_wm_base_add_listener(state.wmBase, &xdgWmBaseListener, NULL);
state.surface = xdg_wm_base_get_xdg_surface(state.wmBase, surface);
xdg_surface_add_listener(state.surface, &xdgSurfaceListener, NULL);
state.toplevel = xdg_surface_get_toplevel(state.surface);
xdg_toplevel_add_listener(state.toplevel, &xdgToplevelListener, NULL);
xdg_toplevel_set_title(state.toplevel, title);
xdg_toplevel_set_app_id(state.toplevel, "looking-glass-client");
if (fullscreen)
xdg_toplevel_set_fullscreen(state.toplevel, NULL);
if (maximize)
xdg_toplevel_set_maximized(state.toplevel);
if (state.decorationManager)
{
state.toplevelDecoration = zxdg_decoration_manager_v1_get_toplevel_decoration(
state.decorationManager, state.toplevel);
if (state.toplevelDecoration)
{
zxdg_toplevel_decoration_v1_set_mode(state.toplevelDecoration,
borderless ?
ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE :
ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
}
}
return true;
}
static void xdg_shellAckConfigureIfNeeded(void)
{
if (state.resizeSerial)
{
xdg_surface_ack_configure(state.surface, state.resizeSerial);
state.resizeSerial = 0;
}
}
static void xdg_setFullscreen(bool fs)
{
if (fs)
xdg_toplevel_set_fullscreen(state.toplevel, NULL);
else
xdg_toplevel_unset_fullscreen(state.toplevel);
}
static bool xdg_getFullscreen(void)
{
return state.fullscreen;
}
static void xdg_minimize(void)
{
xdg_toplevel_set_minimized(state.toplevel);
}
static void xdg_shellResize(int w, int h)
{
if (!state.floating)
return;
state.width = w;
state.height = h;
xdg_surface_set_window_geometry(state.surface, 0, 0, w, h);
waylandNeedsResize();
}
static void xdg_setSize(int w, int h)
{
state.width = w;
state.height = h;
}
static void xdg_getSize(int * w, int * h)
{
*w = state.width;
*h = state.height;
}
static bool xdg_registryGlobalHandler(void * data,
struct wl_registry * registry, uint32_t name, const char * interface,
uint32_t version)
{
if (!strcmp(interface, xdg_wm_base_interface.name))
{
state.wmBase = wl_registry_bind(registry, name,
&xdg_wm_base_interface, 1);
return true;
}
if (!strcmp(interface, zxdg_decoration_manager_v1_interface.name))
{
state.decorationManager = wl_registry_bind(registry, name,
&zxdg_decoration_manager_v1_interface, 1);
return true;
}
return false;
}
static void waylandDisplayCallback(uint32_t events, void * opaque)
{
struct wl_display * display = (struct wl_display *)opaque;
if (events & EPOLLERR)
wl_display_cancel_read(display);
else
wl_display_read_events(display);
wl_display_dispatch_pending(display);
}
static bool xdg_pollInit(struct wl_display * display)
{
state.displayFd = wl_display_get_fd(display);
if (!waylandPollRegister(state.displayFd, waylandDisplayCallback,
display, EPOLLIN))
{
DEBUG_ERROR("Failed register display to epoll: %s", strerror(errno));
return false;
}
return true;
}
void xdg_pollWait(struct wl_display * display, int epollFd,
unsigned int time)
{
while (wl_display_prepare_read(display))
wl_display_dispatch_pending(display);
wl_display_flush(display);
struct epoll_event events[MAX_EPOLL_EVENTS];
int count;
if ((count = epoll_wait(epollFd, events, MAX_EPOLL_EVENTS, time)) < 0)
{
if (errno != EINTR)
DEBUG_INFO("epoll failed: %s", strerror(errno));
wl_display_cancel_read(display);
return;
}
bool sawDisplay = false;
for (int i = 0; i < count; ++i) {
struct WaylandPoll * poll = events[i].data.ptr;
if (!poll->removed)
poll->callback(events[i].events, poll->opaque);
if (poll->fd == state.displayFd)
sawDisplay = true;
}
if (!sawDisplay)
wl_display_cancel_read(display);
}
WL_DesktopOps WLD_xdg =
{
.name = "xdg",
.compositor = "",
.shellInit = xdg_shellInit,
.shellAckConfigureIfNeeded = xdg_shellAckConfigureIfNeeded,
.setFullscreen = xdg_setFullscreen,
.getFullscreen = xdg_getFullscreen,
.minimize = xdg_minimize,
.shellResize = xdg_shellResize,
.setSize = xdg_setSize,
.getSize = xdg_getSize,
.registryGlobalHandler = xdg_registryGlobalHandler,
.pollInit = xdg_pollInit,
.pollWait = xdg_pollWait
};

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -89,18 +89,21 @@ void waylandEGLSwapBuffers(EGLDisplay display, EGLSurface surface, const struct
if (wlWm.needsResize)
{
bool skipResize = false;
wl_egl_window_resize(wlWm.eglWindow, wl_fixed_to_int(wlWm.width * wlWm.scale),
wl_fixed_to_int(wlWm.height * wlWm.scale), 0, 0);
if (wlWm.width == 0 || wlWm.height == 0)
int width, height;
wlWm.desktop->getSize(&width, &height);
wl_egl_window_resize(wlWm.eglWindow, wl_fixed_to_int(width * wlWm.scale),
wl_fixed_to_int(height * wlWm.scale), 0, 0);
if (width == 0 || height == 0)
skipResize = true;
else if (wlWm.fractionalScale)
{
wl_surface_set_buffer_scale(wlWm.surface, 1);
if (!wlWm.viewport)
wlWm.viewport = wp_viewporter_get_viewport(wlWm.viewporter, wlWm.surface);
wp_viewport_set_source(wlWm.viewport, 0, 0, wlWm.width * wlWm.scale, wlWm.height * wlWm.scale);
wp_viewport_set_destination(wlWm.viewport, wlWm.width, wlWm.height);
wp_viewport_set_source(wlWm.viewport, 0, 0, width * wlWm.scale, height * wlWm.scale);
wp_viewport_set_destination(wlWm.viewport, width, height);
}
else
{
@@ -120,18 +123,18 @@ void waylandEGLSwapBuffers(EGLDisplay display, EGLSurface surface, const struct
}
struct wl_region * region = wl_compositor_create_region(wlWm.compositor);
wl_region_add(region, 0, 0, wlWm.width, wlWm.height);
wl_region_add(region, 0, 0, width, height);
wl_surface_set_opaque_region(wlWm.surface, region);
wl_region_destroy(region);
app_handleResizeEvent(wlWm.width, wlWm.height, wl_fixed_to_double(wlWm.scale),
app_handleResizeEvent(width, height, wl_fixed_to_double(wlWm.scale),
(struct Border) {0, 0, 0, 0});
app_invalidateWindow(true);
waylandStopWaitFrame();
wlWm.needsResize = skipResize;
}
waylandShellAckConfigureIfNeeded();
wlWm.desktop->shellAckConfigureIfNeeded();
}
#endif

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -590,10 +590,13 @@ void waylandWarpPointer(int x, int y, bool exiting)
return;
}
int width, height;
wlWm.desktop->getSize(&width, &height);
if (x < 0) x = 0;
else if (x >= wlWm.width) x = wlWm.width - 1;
else if (x >= width) x = width - 1;
if (y < 0) y = 0;
else if (y >= wlWm.height) y = wlWm.height - 1;
else if (y >= height) y = height - 1;
struct wl_region * region = wl_compositor_create_region(wlWm.compositor);
wl_region_add(region, x, y, 1, 1);

View File

@@ -0,0 +1,64 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 59
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _H_WAYLAND_DESKTOP_H_
#define _H_WAYLAND_DESKTOP_H_
#include <stdbool.h>
#include <wayland-client.h>
typedef struct WL_DesktopOps
{
// the friendly name
const char * name;
// the compositor process name to match
const char * compositor;
bool (*shellInit)(
struct wl_display * display, struct wl_surface * surface,
const char * title, bool fullscreen, bool maximize,
bool borderless, bool resizable);
void (*shellAckConfigureIfNeeded)(void);
void (*setFullscreen)(bool fs);
bool (*getFullscreen)(void);
void (*minimize)(void);
void (*shellResize)(int w, int h);
void (*setSize)(int w, int h);
void (*getSize)(int * w, int * h);
bool (*registryGlobalHandler)(
void * data, struct wl_registry * registry,
uint32_t name, const char * interface, uint32_t version);
bool (*pollInit)(struct wl_display * display);
void (*pollWait)(struct wl_display * display, int epollFd, unsigned int time);
}
WL_DesktopOps;
#endif

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -30,23 +30,6 @@
#include "common/debug.h"
#include "common/locking.h"
#ifdef ENABLE_LIBDECOR
#include <libdecor.h>
#endif
#define EPOLL_EVENTS 10 // Maximum number of fds we can process at once in waylandWait
#ifndef ENABLE_LIBDECOR
static void waylandDisplayCallback(uint32_t events, void * opaque)
{
if (events & EPOLLERR)
wl_display_cancel_read(wlWm.display);
else
wl_display_read_events(wlWm.display);
wl_display_dispatch_pending(wlWm.display);
}
#endif
bool waylandPollInit(void)
{
wlWm.epollFd = epoll_create1(EPOLL_CLOEXEC);
@@ -61,58 +44,12 @@ bool waylandPollInit(void)
LG_LOCK_INIT(wlWm.pollLock);
LG_LOCK_INIT(wlWm.pollFreeLock);
#ifndef ENABLE_LIBDECOR
wlWm.displayFd = wl_display_get_fd(wlWm.display);
if (!waylandPollRegister(wlWm.displayFd, waylandDisplayCallback, NULL, EPOLLIN))
{
DEBUG_ERROR("Failed register display to epoll: %s", strerror(errno));
return false;
}
#endif
return true;
return wlWm.desktop->pollInit(wlWm.display);
}
void waylandWait(unsigned int time)
{
#ifdef ENABLE_LIBDECOR
libdecor_dispatch(wlWm.libdecor, 0);
#else
while (wl_display_prepare_read(wlWm.display))
wl_display_dispatch_pending(wlWm.display);
wl_display_flush(wlWm.display);
#endif
struct epoll_event events[EPOLL_EVENTS];
int count;
if ((count = epoll_wait(wlWm.epollFd, events, EPOLL_EVENTS, time)) < 0)
{
if (errno != EINTR)
DEBUG_INFO("epoll failed: %s", strerror(errno));
#ifndef ENABLE_LIBDECOR
wl_display_cancel_read(wlWm.display);
#endif
return;
}
#ifndef ENABLE_LIBDECOR
bool sawDisplay = false;
#endif
for (int i = 0; i < count; ++i) {
struct WaylandPoll * poll = events[i].data.ptr;
if (!poll->removed)
poll->callback(events[i].events, poll->opaque);
#ifndef ENABLE_LIBDECOR
if (poll->fd == wlWm.displayFd)
sawDisplay = true;
#endif
}
#ifndef ENABLE_LIBDECOR
if (!sawDisplay)
wl_display_cancel_read(wlWm.display);
#endif
wlWm.desktop->pollWait(wlWm.display, wlWm.epollFd, time);
INTERLOCKED_SECTION(wlWm.pollFreeLock,
{
struct WaylandPoll * node;

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it

View File

@@ -0,0 +1,71 @@
cmake_minimum_required(VERSION 3.5)
project(wayland_protocol LANGUAGES C)
find_package(PkgConfig)
pkg_check_modules(WAYLAND REQUIRED IMPORTED_TARGET
wayland-client
wayland-cursor
xkbcommon
)
find_program(WAYLAND_SCANNER_EXECUTABLE NAMES wayland-scanner)
add_library(wayland_protocol STATIC
)
macro(wayland_generate protocol_file output_file)
add_custom_command(OUTPUT "${output_file}.h"
COMMAND "${WAYLAND_SCANNER_EXECUTABLE}" client-header "${protocol_file}" "${output_file}.h"
DEPENDS "${protocol_file}"
VERBATIM)
add_custom_command(OUTPUT "${output_file}.c"
COMMAND "${WAYLAND_SCANNER_EXECUTABLE}" private-code "${protocol_file}" "${output_file}.c"
DEPENDS "${protocol_file}"
VERBATIM)
target_sources(wayland_protocol PRIVATE "${output_file}.h" "${output_file}.c")
endmacro()
set(WAYLAND_PROTOCOLS_BASE "${PROJECT_TOP}/repos/wayland-protocols")
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/wayland")
include_directories("${CMAKE_BINARY_DIR}/wayland")
wayland_generate(
"${WAYLAND_PROTOCOLS_BASE}/stable/xdg-shell/xdg-shell.xml"
"${CMAKE_BINARY_DIR}/wayland/wayland-xdg-shell-client-protocol")
wayland_generate(
"${WAYLAND_PROTOCOLS_BASE}/stable/presentation-time/presentation-time.xml"
"${CMAKE_BINARY_DIR}/wayland/wayland-presentation-time-client-protocol")
wayland_generate(
"${WAYLAND_PROTOCOLS_BASE}/stable/viewporter/viewporter.xml"
"${CMAKE_BINARY_DIR}/wayland/wayland-viewporter-client-protocol")
wayland_generate(
"${WAYLAND_PROTOCOLS_BASE}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml"
"${CMAKE_BINARY_DIR}/wayland/wayland-xdg-decoration-unstable-v1-client-protocol")
wayland_generate(
"${WAYLAND_PROTOCOLS_BASE}/unstable/relative-pointer/relative-pointer-unstable-v1.xml"
"${CMAKE_BINARY_DIR}/wayland/wayland-relative-pointer-unstable-v1-client-protocol")
wayland_generate(
"${WAYLAND_PROTOCOLS_BASE}/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml"
"${CMAKE_BINARY_DIR}/wayland/wayland-pointer-constraints-unstable-v1-client-protocol")
wayland_generate(
"${WAYLAND_PROTOCOLS_BASE}/unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml"
"${CMAKE_BINARY_DIR}/wayland/wayland-keyboard-shortcuts-inhibit-unstable-v1-client-protocol")
wayland_generate(
"${WAYLAND_PROTOCOLS_BASE}/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml"
"${CMAKE_BINARY_DIR}/wayland/wayland-idle-inhibit-unstable-v1-client-protocol")
wayland_generate(
"${WAYLAND_PROTOCOLS_BASE}/unstable/xdg-output/xdg-output-unstable-v1.xml"
"${CMAKE_BINARY_DIR}/wayland/wayland-xdg-output-unstable-v1-client-protocol")
wayland_generate(
"${WAYLAND_PROTOCOLS_BASE}/staging/xdg-activation/xdg-activation-v1.xml"
"${CMAKE_BINARY_DIR}/wayland/wayland-xdg-activation-v1-client-protocol")
target_link_libraries(wayland_protocol
PkgConfig::WAYLAND
)
target_include_directories(wayland_protocol
PUBLIC
"${CMAKE_BINARY_DIR}/wayland"
)

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -40,13 +40,6 @@ static void registryGlobalHandler(void * data, struct wl_registry * registry,
wlWm.compositor = wl_registry_bind(wlWm.registry, name,
// we only need v3 to run, but v4 can use eglSwapBuffersWithDamageKHR
&wl_compositor_interface, version > 4 ? 4 : version);
#ifndef ENABLE_LIBDECOR
else if (!strcmp(interface, xdg_wm_base_interface.name))
wlWm.xdgWmBase = wl_registry_bind(wlWm.registry, name, &xdg_wm_base_interface, 1);
else if (!strcmp(interface, zxdg_decoration_manager_v1_interface.name))
wlWm.xdgDecorationManager = wl_registry_bind(wlWm.registry, name,
&zxdg_decoration_manager_v1_interface, 1);
#endif
else if (!strcmp(interface, wp_presentation_interface.name))
wlWm.presentation = wl_registry_bind(wlWm.registry, name,
&wp_presentation_interface, 1);
@@ -75,6 +68,9 @@ static void registryGlobalHandler(void * data, struct wl_registry * registry,
else if (!strcmp(interface, xdg_activation_v1_interface.name))
wlWm.xdgActivation = wl_registry_bind(wlWm.registry, name,
&xdg_activation_v1_interface, 1);
else if (wlWm.desktop->registryGlobalHandler(
data, registry, name, interface, version))
return;
}
static void registryGlobalRemoveHandler(void * data,

View File

@@ -1,178 +0,0 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 59
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "wayland.h"
#include <errno.h>
#include <stdbool.h>
#include <string.h>
#include <sys/epoll.h>
#include <libdecor.h>
#include <wayland-client.h>
#include "app.h"
#include "common/debug.h"
struct libdecor_configuration {
uint32_t serial;
bool has_window_state;
enum libdecor_window_state window_state;
bool has_size;
int window_width;
int window_height;
};
static void libdecorHandleError(struct libdecor * context, enum libdecor_error error,
const char *message)
{
DEBUG_ERROR("Got libdecor error (%d): %s", error, message);
}
static void libdecorFrameConfigure(struct libdecor_frame * frame,
struct libdecor_configuration * configuration, void * opaque)
{
if (!wlWm.configured)
{
xdg_surface_ack_configure(libdecor_frame_get_xdg_surface(frame), configuration->serial);
wlWm.configured = true;
return;
}
int width, height;
if (libdecor_configuration_get_content_size(configuration, frame, &width, &height))
{
wlWm.width = width;
wlWm.height = height;
struct libdecor_state * state = libdecor_state_new(wlWm.width, wlWm.height);
libdecor_frame_commit(wlWm.libdecorFrame, state, NULL);
libdecor_state_free(state);
}
enum libdecor_window_state windowState;
if (libdecor_configuration_get_window_state(configuration, &windowState))
wlWm.fullscreen = windowState & LIBDECOR_WINDOW_STATE_FULLSCREEN;
wlWm.needsResize = true;
wlWm.resizeSerial = configuration->serial;
app_invalidateWindow(true);
waylandStopWaitFrame();
}
static void libdecorFrameClose(struct libdecor_frame * frame, void * opaque)
{
app_handleCloseEvent();
}
static void libdecorFrameCommit(struct libdecor_frame * frame, void * opaque)
{
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
static struct libdecor_interface libdecorListener = {
libdecorHandleError,
};
static struct libdecor_frame_interface libdecorFrameListener = {
libdecorFrameConfigure,
libdecorFrameClose,
libdecorFrameCommit,
};
#pragma GCC diagnostic pop
static void libdecorCallback(uint32_t events, void * opaque)
{
libdecor_dispatch(wlWm.libdecor, 0);
}
bool waylandShellInit(const char * title, bool fullscreen, bool maximize, bool borderless, bool resizable)
{
wlWm.libdecor = libdecor_new(wlWm.display, &libdecorListener);
wlWm.libdecorFrame = libdecor_decorate(wlWm.libdecor, wlWm.surface, &libdecorFrameListener, NULL);
libdecor_frame_set_app_id(wlWm.libdecorFrame, "looking-glass-client");
libdecor_frame_set_title(wlWm.libdecorFrame, title);
libdecor_frame_map(wlWm.libdecorFrame);
if (resizable)
libdecor_frame_set_capabilities(wlWm.libdecorFrame, LIBDECOR_ACTION_RESIZE);
else
libdecor_frame_unset_capabilities(wlWm.libdecorFrame, LIBDECOR_ACTION_RESIZE);
while (!wlWm.configured)
libdecor_dispatch(wlWm.libdecor, 0);
if (!waylandPollRegister(libdecor_get_fd(wlWm.libdecor), libdecorCallback, NULL, EPOLLIN))
{
DEBUG_ERROR("Failed register display to epoll: %s", strerror(errno));
return false;
}
return true;
}
void waylandShellAckConfigureIfNeeded(void)
{
if (wlWm.resizeSerial)
{
xdg_surface_ack_configure(libdecor_frame_get_xdg_surface(wlWm.libdecorFrame), wlWm.resizeSerial);
wlWm.resizeSerial = 0;
}
}
void waylandSetFullscreen(bool fs)
{
if (fs)
libdecor_frame_set_fullscreen(wlWm.libdecorFrame, NULL);
else
libdecor_frame_unset_fullscreen(wlWm.libdecorFrame);
libdecor_frame_set_visibility(wlWm.libdecorFrame, !fs);
}
bool waylandGetFullscreen(void)
{
return wlWm.fullscreen;
}
void waylandMinimize(void)
{
libdecor_frame_set_minimized(wlWm.libdecorFrame);
}
void waylandShellResize(int w, int h)
{
if (!libdecor_frame_is_floating(wlWm.libdecorFrame))
return;
wlWm.width = w;
wlWm.height = h;
struct libdecor_state * state = libdecor_state_new(w, h);
libdecor_frame_commit(wlWm.libdecorFrame, state, NULL);
libdecor_state_free(state);
wlWm.needsResize = true;
app_invalidateWindow(true);
waylandStopWaitFrame();
}

View File

@@ -1,160 +0,0 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 59
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "wayland.h"
#include <stdbool.h>
#include <wayland-client.h>
#include "app.h"
#include "common/debug.h"
// XDG WM base listeners.
static void xdgWmBasePing(void * data, struct xdg_wm_base * xdgWmBase, uint32_t serial)
{
xdg_wm_base_pong(xdgWmBase, serial);
}
static const struct xdg_wm_base_listener xdgWmBaseListener = {
.ping = xdgWmBasePing,
};
// XDG Surface listeners.
static void xdgSurfaceConfigure(void * data, struct xdg_surface * xdgSurface,
uint32_t serial)
{
if (wlWm.configured)
{
wlWm.needsResize = true;
wlWm.resizeSerial = serial;
app_invalidateWindow(true);
waylandStopWaitFrame();
}
else
{
xdg_surface_ack_configure(xdgSurface, serial);
wlWm.configured = true;
}
}
static const struct xdg_surface_listener xdgSurfaceListener = {
.configure = xdgSurfaceConfigure,
};
// XDG Toplevel listeners.
static void xdgToplevelConfigure(void * data, struct xdg_toplevel * xdgToplevel,
int32_t width, int32_t height, struct wl_array * states)
{
wlWm.width = width;
wlWm.height = height;
wlWm.fullscreen = false;
enum xdg_toplevel_state * state;
wl_array_for_each(state, states)
{
if (*state == XDG_TOPLEVEL_STATE_FULLSCREEN)
wlWm.fullscreen = true;
}
}
static void xdgToplevelClose(void * data, struct xdg_toplevel * xdgToplevel)
{
app_handleCloseEvent();
}
static const struct xdg_toplevel_listener xdgToplevelListener = {
.configure = xdgToplevelConfigure,
.close = xdgToplevelClose,
};
bool waylandShellInit(const char * title, bool fullscreen, bool maximize, bool borderless, bool resizable)
{
if (!wlWm.xdgWmBase)
{
DEBUG_ERROR("Compositor missing xdg_wm_base, will not proceed");
return false;
}
xdg_wm_base_add_listener(wlWm.xdgWmBase, &xdgWmBaseListener, NULL);
wlWm.xdgSurface = xdg_wm_base_get_xdg_surface(wlWm.xdgWmBase, wlWm.surface);
xdg_surface_add_listener(wlWm.xdgSurface, &xdgSurfaceListener, NULL);
wlWm.xdgToplevel = xdg_surface_get_toplevel(wlWm.xdgSurface);
xdg_toplevel_add_listener(wlWm.xdgToplevel, &xdgToplevelListener, NULL);
xdg_toplevel_set_title(wlWm.xdgToplevel, title);
xdg_toplevel_set_app_id(wlWm.xdgToplevel, "looking-glass-client");
if (fullscreen)
xdg_toplevel_set_fullscreen(wlWm.xdgToplevel, NULL);
if (maximize)
xdg_toplevel_set_maximized(wlWm.xdgToplevel);
if (wlWm.xdgDecorationManager)
{
wlWm.xdgToplevelDecoration = zxdg_decoration_manager_v1_get_toplevel_decoration(
wlWm.xdgDecorationManager, wlWm.xdgToplevel);
if (wlWm.xdgToplevelDecoration)
{
zxdg_toplevel_decoration_v1_set_mode(wlWm.xdgToplevelDecoration,
borderless ?
ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE :
ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
}
}
return true;
}
void waylandShellAckConfigureIfNeeded(void)
{
if (wlWm.resizeSerial)
{
xdg_surface_ack_configure(wlWm.xdgSurface, wlWm.resizeSerial);
wlWm.resizeSerial = 0;
}
}
void waylandSetFullscreen(bool fs)
{
if (fs)
xdg_toplevel_set_fullscreen(wlWm.xdgToplevel, NULL);
else
xdg_toplevel_unset_fullscreen(wlWm.xdgToplevel);
}
bool waylandGetFullscreen(void)
{
return wlWm.fullscreen;
}
void waylandMinimize(void)
{
xdg_toplevel_set_minimized(wlWm.xdgToplevel);
}
void waylandShellResize(int w, int h)
{
//TODO: Implement resize for XDG.
}

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -24,10 +24,13 @@
#include <signal.h>
#include <string.h>
#include <wayland-client.h>
#include <sys/socket.h>
#include "common/debug.h"
#include "common/option.h"
#include "dynamic/wayland_desktops.h"
static struct Option waylandOptions[] =
{
{
@@ -68,18 +71,69 @@ static bool waylandProbe(void)
return getenv("WAYLAND_DISPLAY") != NULL;
}
static bool getCompositor(char * dst, size_t size)
{
int fd = wl_display_get_fd(wlWm.display);
struct ucred ucred;
socklen_t len = sizeof(struct ucred);
if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == -1)
{
DEBUG_ERROR("Failed to get the pid of the socket");
return false;
}
char path[64];
snprintf(path, sizeof(path), "/proc/%d/comm", ucred.pid);
FILE *fp = fopen(path, "r");
if (!fp)
{
DEBUG_ERROR("Failed to open %s", path);
return false;
}
if (!fgets(dst, size, fp))
{
DEBUG_ERROR("Failed to read %s", path);
fclose(fp);
return false;
}
fclose(fp);
dst[strlen(dst) - 1] = 0;
return true;
}
static bool waylandInit(const LG_DSInitParams params)
{
memset(&wlWm, 0, sizeof(wlWm));
wlWm.desktop = WL_Desktops[0];
wlWm.display = wl_display_connect(NULL);
if (!wlWm.display)
return false;
// select the desktop interface based on the compositor process name
char compositor[1024];
if (getCompositor(compositor, sizeof(compositor)))
{
DEBUG_INFO("Compositor: %s", compositor);
for(int i = 0; i < WL_DESKTOP_COUNT; ++i)
if (strcmp(WL_Desktops[i]->compositor, compositor) == 0)
{
wlWm.desktop = WL_Desktops[0];
break;
}
}
else
DEBUG_WARN("Compositor: UNKNOWN");
DEBUG_INFO("Selected : %s", wlWm.desktop->name);
wl_list_init(&wlWm.surfaceOutputs);
wlWm.warpSupport = option_get_bool("wayland", "warpSupport");
wlWm.useFractionalScale = option_get_bool("wayland", "fractionScale");
wlWm.display = wl_display_connect(NULL);
wlWm.width = params.w;
wlWm.height = params.h;
if (!waylandPollInit())
return false;
@@ -104,7 +158,9 @@ static bool waylandInit(const LG_DSInitParams params)
if (!waylandInputInit())
return false;
if (!waylandWindowInit(params.title, params.fullscreen, params.maximize, params.borderless, params.resizable))
wlWm.desktop->setSize(params.w, params.h);
if (!waylandWindowInit(params.title, params.fullscreen, params.maximize,
params.borderless, params.resizable))
return false;
if (!waylandEGLInit(params.w, params.h))
@@ -115,9 +171,6 @@ static bool waylandInit(const LG_DSInitParams params)
return false;
#endif
wlWm.width = params.w;
wlWm.height = params.h;
return true;
}
@@ -152,6 +205,28 @@ static bool waylandGetProp(LG_DSProperty prop, void * ret)
return false;
}
void waylandNeedsResize(void)
{
wlWm.needsResize = true;
app_invalidateWindow(true);
waylandStopWaitFrame();
}
static void waylandSetFullscreen(bool fs)
{
wlWm.desktop->setFullscreen(fs);
}
static bool waylandGetFullscreen(void)
{
return wlWm.desktop->getFullscreen();
}
static void waylandMinimize(void)
{
wlWm.desktop->minimize();
}
struct LG_DisplayServerOps LGDS_Wayland =
{
.name = "Wayland",

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -37,11 +37,10 @@
#include "common/countedbuffer.h"
#include "common/ringbuffer.h"
#include "interface/displayserver.h"
#include "interface/desktop.h"
#include "wayland-xdg-shell-client-protocol.h"
#include "wayland-presentation-time-client-protocol.h"
#include "wayland-viewporter-client-protocol.h"
#include "wayland-xdg-decoration-unstable-v1-client-protocol.h"
#include "wayland-keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h"
#include "wayland-pointer-constraints-unstable-v1-client-protocol.h"
#include "wayland-relative-pointer-unstable-v1-client-protocol.h"
@@ -100,6 +99,8 @@ struct WaylandDSState
bool pointerInSurface;
bool focusedOnSurface;
WL_DesktopOps * desktop;
struct wl_display * display;
struct wl_surface * surface;
struct wl_registry * registry;
@@ -107,12 +108,9 @@ struct WaylandDSState
struct wl_shm * shm;
struct wl_compositor * compositor;
int32_t width, height;
wl_fixed_t scale;
bool fractionalScale;
bool needsResize;
bool fullscreen;
uint32_t resizeSerial;
bool configured;
bool warpSupport;
double cursorX, cursorY;
@@ -133,17 +131,6 @@ struct WaylandDSState
RingBuffer photonTimings;
GraphHandle photonGraph;
#ifdef ENABLE_LIBDECOR
struct libdecor * libdecor;
struct libdecor_frame * libdecorFrame;
#else
struct xdg_wm_base * xdgWmBase;
struct xdg_surface * xdgSurface;
struct xdg_toplevel * xdgToplevel;
struct zxdg_decoration_manager_v1 * xdgDecorationManager;
struct zxdg_toplevel_decoration_v1 * xdgToplevelDecoration;
#endif
const char * cursorThemeName;
int cursorSize;
int cursorScale;
@@ -313,14 +300,6 @@ void waylandPresentationFree(void);
bool waylandRegistryInit(void);
void waylandRegistryFree(void);
// shell module
bool waylandShellInit(const char * title, bool fullscreen, bool maximize, bool borderless, bool resizable);
void waylandShellAckConfigureIfNeeded(void);
void waylandSetFullscreen(bool fs);
bool waylandGetFullscreen(void);
void waylandMinimize(void);
void waylandShellResize(int w, int h);
// window module
bool waylandWindowInit(const char * title, bool fullscreen, bool maximize, bool borderless, bool resizable);
void waylandWindowFree(void);
@@ -330,3 +309,4 @@ bool waylandIsValidPointerPos(int x, int y);
bool waylandWaitFrame(void);
void waylandSkipFrame(void);
void waylandStopWaitFrame(void);
void waylandNeedsResize(void);

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -112,7 +112,8 @@ bool waylandWindowInit(const char * title, bool fullscreen, bool maximize, bool
wl_surface_add_listener(wlWm.surface, &wlSurfaceListener, NULL);
if (!waylandShellInit(title, fullscreen, maximize, borderless, resizable))
if (!wlWm.desktop->shellInit(wlWm.display, wlWm.surface,
title, fullscreen, maximize, borderless, resizable))
return false;
wl_surface_commit(wlWm.surface);
@@ -127,12 +128,14 @@ void waylandWindowFree(void)
void waylandSetWindowSize(int x, int y)
{
waylandShellResize(x, y);
wlWm.desktop->shellResize(x, y);
}
bool waylandIsValidPointerPos(int x, int y)
{
return x >= 0 && x < wlWm.width && y >= 0 && y < wlWm.height;
int width, height;
wlWm.desktop->getSize(&width, &height);
return x >= 0 && x < width && y >= 0 && y < height;
}
static void frameHandler(void * opaque, struct wl_callback * callback, unsigned int data)

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.0)
cmake_minimum_required(VERSION 3.5)
project(displayserver_X11 LANGUAGES C)
find_package(PkgConfig)
@@ -17,6 +17,10 @@ add_library(displayserver_X11 STATIC
x11.c
atoms.c
clipboard.c
cursor.c
wm/default.c
wm/i3.c
)
add_definitions(-D GLX_GLXEXT_PROTOTYPES)
@@ -24,9 +28,10 @@ add_definitions(-D GLX_GLXEXT_PROTOTYPES)
target_link_libraries(displayserver_X11
PkgConfig::DISPLAYSERVER_X11
lg_common
lg_resources
)
target_include_directories(displayserver_X11
PRIVATE
src
.
)

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it

View File

@@ -0,0 +1,105 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 59
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "cursor.h"
#include "common/util.h"
#include <string.h>
#include <errno.h>
struct MemFile
{
const char * data;
int size;
int pos;
};
static int x11cursor_read(XcursorFile *file, unsigned char * buf, int len)
{
struct MemFile * f = (struct MemFile *)file->closure;
if (f->pos == f->size)
return 0;
len = min(f->size - f->pos, len);
memcpy(buf, f->data + f->pos, len);
f->pos += len;
return len;
}
static int x11cursor_write(XcursorFile *file, unsigned char * buf, int len)
{
errno = -EINVAL;
return -1;
}
static int x11cursor_seek(XcursorFile *file, long offset, int whence)
{
struct MemFile * f = (struct MemFile *)file->closure;
long target;
switch(whence)
{
case SEEK_SET:
target = offset;
break;
case SEEK_CUR:
target = f->pos + offset;
break;
case SEEK_END:
target = f->size + offset;
break;
default:
errno = -EINVAL;
return -1;
}
if (target < 0 || target > f->size)
{
errno = -EINVAL;
return -1;
}
f->pos = target;
return target;
}
XcursorImages * x11cursor_load(const char * cursor, int size)
{
struct MemFile closure =
{
.data = cursor,
.size = size,
.pos = 0
};
XcursorFile f =
{
.closure = &closure,
.read = x11cursor_read,
.write = x11cursor_write,
.seek = x11cursor_seek
};
return XcursorXcFileLoadAllImages(&f);
}

View File

@@ -0,0 +1,29 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 59
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _H_X11DS_CURSOR_
#define _H_X11DS_CURSOR_
#include <X11/Xlib.h>
#include <X11/Xcursor/Xcursor.h>
XcursorImages * x11cursor_load(const char * cursor, int size);
#endif

View File

@@ -0,0 +1,39 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 59
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _H_X11DS_WM_
#define _H_X11DS_WM_
#include <stdint.h>
#include <stdbool.h>
typedef struct X11WM
{
void (*setup)(void);
bool (*init)(void);
void (*deinit)(void);
void (*setFullscreen)(bool enable);
}
X11WM;
extern X11WM X11WM_Default;
extern X11WM X11WM_i3;
#endif

View File

@@ -0,0 +1,71 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 59
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _H_X11DS_WM_DEFAULT_
#define _H_X11DS_WM_DEFAULT_
#include "wm.h"
#include "x11.h"
#include "atoms.h"
static void wm_default_setup(void)
{
}
static bool wm_default_init(void)
{
return true;
}
static void wm_default_deinit(void)
{
}
static void wm_default_setFullscreen(bool enable)
{
XEvent e =
{
.xclient = {
.type = ClientMessage,
.send_event = true,
.message_type = x11atoms._NET_WM_STATE,
.format = 32,
.window = x11.window,
.data.l = {
enable ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE,
x11atoms._NET_WM_STATE_FULLSCREEN,
0
}
}
};
XSendEvent(x11.display, DefaultRootWindow(x11.display), False,
SubstructureNotifyMask | SubstructureRedirectMask, &e);
};
X11WM X11WM_Default =
{
.setup = wm_default_setup,
.init = wm_default_init,
.deinit = wm_default_deinit,
.setFullscreen = wm_default_setFullscreen
};
#endif

View File

@@ -0,0 +1,194 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 59
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _H_X11DS_WM_DEFAULT_
#define _H_X11DS_WM_DEFAULT_
#include "wm.h"
#include "x11.h"
#include "atoms.h"
#include "common/debug.h"
#include "common/option.h"
#include "common/util.h"
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
static struct Option options[] =
{
// app options
{
.module = "i3",
.name = "globalFullScreen",
.description = "Use i3's global full screen feature (spans all monitors)",
.type = OPTION_TYPE_BOOL,
.value.x_bool = false,
},
{0}
};
struct i3state
{
int sock;
bool globalFullScreen;
};
static struct i3state i3;
static void wm_i3_setup(void)
{
option_register(options);
}
static bool wm_i3_init(void)
{
memset(&i3, 0, sizeof(i3));
i3.globalFullScreen = option_get_bool("i3", "globalFullScreen");
FILE * fd = popen("i3 --get-socketpath", "r");
if (!fd)
return false;
struct sockaddr_un addr = { .sun_family = AF_UNIX };
char path[sizeof(addr.sun_path)];
int pathLen;
if ((pathLen = fread(path, 1, sizeof(path), fd)) <= 0)
{
pclose(fd);
return false;
}
pclose(fd);
if(path[pathLen-1] == '\n')
--pathLen;
path[pathLen] = '\0';
i3.sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (i3.sock < 0)
{
DEBUG_ERROR("Failed to create socket for i3 IPC");
return false;
}
strncpy(addr.sun_path, path, sizeof(addr.sun_path));
if (connect(i3.sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
DEBUG_ERROR("Failed to connect to the i3 IPC socket");
perror("connect");
goto err_socket;
}
DEBUG_INFO("i3 IPC Connected");
return true;
err_socket:
close(i3.sock);
return false;
}
static void wm_i3_deinit(void)
{
close(i3.sock);
}
static void wm_i3_setFullscreen(bool enable)
{
if (!i3.globalFullScreen)
{
X11WM_Default.setFullscreen(enable);
return;
}
struct i3Msg
{
char magic[6];
uint32_t length;
uint32_t type;
char payload[0];
}
__attribute__((packed));
#define I3_IPC_TYPE_RUN_COMMAND 0
char cmd[128];
int cmdLen = snprintf(cmd, sizeof(cmd),
"[id=%lu] fullscreen toggle global",
x11.window);
struct i3Msg *msg = alloca(sizeof(struct i3Msg) + cmdLen);
memcpy(msg->magic, "i3-ipc", 6);
msg->length = cmdLen;
msg->type = I3_IPC_TYPE_RUN_COMMAND;
memcpy(msg->payload, cmd, cmdLen);
int msgSize = sizeof(*msg) + msg->length;
char * buf = (char *)msg;
while(msgSize)
{
int wrote = write(i3.sock, buf, msgSize);
if (wrote <= 0)
{
DEBUG_WARN("i3 IPC communication failure");
return;
}
buf += wrote;
msgSize -= wrote;
}
if ((msgSize = read(i3.sock, msg, sizeof(*msg))) < 0)
{
DEBUG_WARN("i3 IPC read failure");
return;
}
if (memcmp(msg->magic, "i3-ipc", 6) != 0 ||
msg->type != I3_IPC_TYPE_RUN_COMMAND)
{
DEBUG_WARN("i3 IPC unexpected reply");
return;
}
// read and discard the payload
while(msg->length)
{
int len = read(i3.sock, cmd, min(msg->length, sizeof(cmd)));
if (len <= 0)
{
DEBUG_WARN("i3 IPC failed to read payload");
return;
}
msg->length -= len;
}
};
X11WM X11WM_i3 =
{
.setup = wm_i3_setup,
.init = wm_i3_init,
.deinit = wm_i3_deinit,
.setFullscreen = wm_i3_setFullscreen
};
#endif

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -23,7 +23,11 @@
#include "x11.h"
#include "atoms.h"
#include "clipboard.h"
#include "cursor.h"
#include "resources/icondata.h"
#include "resources/no-input-cursor/16.xcur.h"
#include "resources/no-input-cursor/32.xcur.h"
#include <string.h>
#include <unistd.h>
@@ -53,10 +57,6 @@
#include "common/event.h"
#include "util.h"
#define _NET_WM_STATE_REMOVE 0
#define _NET_WM_STATE_ADD 1
#define _NET_WM_STATE_TOGGLE 2
struct X11DSState x11;
struct MwmHints
@@ -166,6 +166,8 @@ static void x11DoPresent(uint64_t msc)
static void x11Setup(void)
{
X11WM_Default.setup();
X11WM_i3 .setup();
}
static bool x11Probe(void)
@@ -230,6 +232,8 @@ static void x11CheckEWMHSupport(void)
DEBUG_INFO("EWMH-complient window manager detected: %s", wmName);
x11.ewmhSupport = true;
if (strcmp(wmName, "i3") == 0)
x11.wm = &X11WM_i3;
XFree(wmName);
out_supported:
@@ -242,17 +246,37 @@ out:
return;
}
static int x11ErrorHandler(Display * display, XErrorEvent * error)
{
char errorText[1024];
XGetErrorText(display, error->error_code, errorText, sizeof(errorText));
DEBUG_ERROR("X11 Error: %s", errorText);
DEBUG_PRINT_BACKTRACE();
return 0;
}
static int x11IOErrorHandler(Display * display)
{
DEBUG_FATAL("Fatal X11 IO Error");
return 0;
}
static bool x11Init(const LG_DSInitParams params)
{
XIDeviceInfo *devinfo;
int count;
int event, error;
XSetErrorHandler(x11ErrorHandler);
XSetIOErrorHandler(x11IOErrorHandler);
memset(&x11, 0, sizeof(x11));
x11.xValuator = -1;
x11.yValuator = -1;
x11.display = XOpenDisplay(NULL);
x11.display = XOpenDisplay(NULL);
x11.jitRender = params.jitRender;
x11.wm = &X11WM_Default;
XSetWindowAttributes swa =
{
@@ -350,6 +374,16 @@ static bool x11Init(const LG_DSInitParams params)
// check for Extended Window Manager Hints support
x11CheckEWMHSupport();
if (!x11.wm->init())
{
x11.wm = &X11WM_Default;
if (!x11.wm->init())
{
DEBUG_ERROR("Failed to initialize the X11 window manager subsystem");
goto fail_window;
}
}
if (x11atoms._NET_WM_PID)
{
pid_t pid = getpid();
@@ -457,7 +491,7 @@ static bool x11Init(const LG_DSInitParams params)
if (XIQueryVersion(x11.display, &major, &minor) != Success)
{
DEBUG_ERROR("Failed to query the XInput version");
return false;
goto fail_window;
}
DEBUG_INFO("X11 XInput %d.%d in use", major, minor);
@@ -596,29 +630,17 @@ static bool x11Init(const LG_DSInitParams params)
XFreePixmap(x11.display, temp);
}
/* create the square cursor */
{
static char data[] = { 0x07, 0x05, 0x07 };
static char mask[] = { 0xff, 0xff, 0xff };
XcursorImages * images;
if (params.largeCursorDot)
images = x11cursor_load(b_no_input_cursor_32_xcur,
b_no_input_cursor_32_xcur_size);
else
images = x11cursor_load(b_no_input_cursor_16_xcur,
b_no_input_cursor_16_xcur_size);
Colormap cmap = DefaultColormap(x11.display, DefaultScreen(x11.display));
XColor colors[2] =
{
{ .pixel = BlackPixelOfScreen(DefaultScreenOfDisplay(x11.display)) },
{ .pixel = WhitePixelOfScreen(DefaultScreenOfDisplay(x11.display)) }
};
XQueryColors(x11.display, cmap, colors, 2);
Pixmap img = XCreateBitmapFromData(x11.display, x11.window, data, 3, 3);
Pixmap msk = XCreateBitmapFromData(x11.display, x11.window, mask, 3, 3);
x11.cursors[LG_POINTER_SQUARE] = XCreatePixmapCursor(x11.display, img, msk,
&colors[0], &colors[1], 1, 1);
XFreePixmap(x11.display, img);
XFreePixmap(x11.display, msk);
}
x11.cursors[LG_POINTER_SQUARE] =
XcursorImagesLoadCursor(x11.display, images);
XcursorImagesDestroy(images);
/* initialize the rest of the cursors */
const char * cursorLookup[LG_POINTER_COUNT] = {
@@ -762,6 +784,7 @@ static void x11Free(void)
if (x11.keysyms)
XFree(x11.keysyms);
x11.wm->deinit();
XCloseDisplay(x11.display);
}
@@ -1152,6 +1175,46 @@ static void x11XInputEvent(XGenericEventCookie *cookie)
app_updateCursorPos(xie->event_x, xie->event_y);
app_handleEnterEvent(false);
x11.entered = false;
/**
* Because there is a race with the pointer ungrab the enter event for the
* next window is sometimes sent with the mode NotifyUngrab, unfortunatly
* some window managers such as i3 will ignore these which breaks focus
* follows mouse mode. To correct this we generate and send a normal
* EnterNotify event.
*/
int root_x, root_y, win_x, win_y;
Window root_win, child_win;
unsigned int mask;
XQueryPointer(x11.display, DefaultRootWindow(x11.display), &root_win,
&child_win, &root_x, &root_y, &win_x, &win_y, &mask);
int target_x, target_y;
Window target_root;
XTranslateCoordinates(x11.display, DefaultRootWindow(x11.display),
child_win, root_x, root_y, &target_x, &target_y, &target_root);
XEvent event;
memset(&event, 0, sizeof(event));
event.type = EnterNotify;
event.xcrossing.serial = 0;
event.xcrossing.send_event = True;
event.xcrossing.display = x11.display;
event.xcrossing.window = child_win;
event.xcrossing.root = root_win;
event.xcrossing.subwindow = child_win;
event.xcrossing.time = CurrentTime;
event.xcrossing.mode = NotifyNormal;
event.xcrossing.detail = NotifyNonlinear;
event.xcrossing.same_screen = True;
event.xcrossing.focus = False;
event.xcrossing.x = target_x;
event.xcrossing.y = target_y;
event.xcrossing.x_root = root_x;
event.xcrossing.y_root = root_y;
XSendEvent(x11.display, child_win, True, EnterWindowMask, &event);
XFlush(x11.display);
return;
}
@@ -1905,24 +1968,7 @@ static void x11SetFullscreen(bool fs)
if (x11.fullscreen == fs)
return;
XEvent e =
{
.xclient = {
.type = ClientMessage,
.send_event = true,
.message_type = x11atoms._NET_WM_STATE,
.format = 32,
.window = x11.window,
.data.l = {
fs ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE,
x11atoms._NET_WM_STATE_FULLSCREEN,
0
}
}
};
XSendEvent(x11.display, DefaultRootWindow(x11.display), False,
SubstructureNotifyMask | SubstructureRedirectMask, &e);
x11.wm->setFullscreen(fs);
}
static bool x11GetFullscreen(void)

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -33,6 +33,7 @@
#include "interface/displayserver.h"
#include "common/thread.h"
#include "common/types.h"
#include "wm.h"
enum Modifiers
{
@@ -48,11 +49,16 @@ enum Modifiers
#define MOD_COUNT (MOD_SUPER_RIGHT + 1)
#define _NET_WM_STATE_REMOVE 0
#define _NET_WM_STATE_ADD 1
#define _NET_WM_STATE_TOGGLE 2
struct X11DSState
{
Display * display;
Window window;
XVisualInfo * visual;
X11WM * wm;
int minKeycode, maxKeycode;
int symsPerKeycode;

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -90,6 +90,7 @@ typedef struct LG_DSInitParams
bool resizable;
bool borderless;
bool maximize;
bool largeCursorDot;
// if true the renderer requires an OpenGL context
bool opengl;

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -72,8 +72,12 @@ LG_RendererRotate;
typedef struct LG_RendererFormat
{
FrameType type; // frame type
bool hdr; // if the frame is HDR or not
bool hdrPQ; // if the HDR content is PQ mapped
unsigned int screenWidth; // actual width of the host
unsigned int screenHeight; // actual height of the host
unsigned int dataWidth; // the width of the packed data
unsigned int dataHeight; // the height of the packed data
unsigned int frameWidth; // width of frame transmitted
unsigned int frameHeight; // height of frame transmitted
unsigned int stride; // scanline width (zero if compresed)

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.0)
cmake_minimum_required(VERSION 3.5)
project(renderers LANGUAGES C)
set(RENDERER_H "${CMAKE_BINARY_DIR}/include/dynamic/renderers.h")

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.0)
cmake_minimum_required(VERSION 3.5)
project(renderer_EGL LANGUAGES C CXX)
find_package(PkgConfig)
@@ -56,6 +56,7 @@ build_shaders(
shader/damage.vert
shader/damage.frag
shader/basic.vert
shader/convert_24bit.frag
shader/ffx_cas.frag
shader/ffx_fsr1_easu.frag
shader/ffx_fsr1_rcas.frag
@@ -87,6 +88,7 @@ add_library(renderer_EGL STATIC
postprocess.c
ffx.c
filter.c
filter_24bit.c
filter_ffx_cas.c
filter_ffx_fsr1.c
filter_downscale.c

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -100,7 +100,7 @@ static bool cursorTexInit(struct CursorTex * t,
}
if (!egl_shaderCompile(t->shader,
vertex_code, vertex_size, fragment_code, fragment_size))
vertex_code, vertex_size, fragment_code, fragment_size, false, NULL))
{
DEBUG_ERROR("Failed to compile the cursor shader");
return false;
@@ -277,7 +277,7 @@ struct CursorState egl_cursorRender(EGL_Cursor * cursor,
}
egl_textureSetup(cursor->mono.texture, EGL_PF_BGRA,
cursor->width, cursor->height, sizeof(xor[0]));
cursor->width, cursor->height, cursor->width, sizeof(xor[0]));
egl_textureUpdate(cursor->mono.texture, (uint8_t *)xor, true);
}
// fall through
@@ -285,7 +285,7 @@ struct CursorState egl_cursorRender(EGL_Cursor * cursor,
case LG_CURSOR_COLOR:
{
egl_textureSetup(cursor->norm.texture, EGL_PF_BGRA,
cursor->width, cursor->height, cursor->stride);
cursor->width, cursor->height, cursor->width, cursor->stride);
egl_textureUpdate(cursor->norm.texture, data, true);
break;
}
@@ -311,9 +311,9 @@ struct CursorState egl_cursorRender(EGL_Cursor * cursor,
}
egl_textureSetup(cursor->norm.texture, EGL_PF_BGRA,
cursor->width, cursor->height, sizeof(and[0]));
cursor->width, cursor->height, cursor->width, sizeof(and[0]));
egl_textureSetup(cursor->mono.texture, EGL_PF_BGRA,
cursor->width, cursor->height, sizeof(xor[0]));
cursor->width, cursor->height, cursor->width, sizeof(xor[0]));
egl_textureUpdate(cursor->norm.texture, (uint8_t *)and, true);
egl_textureUpdate(cursor->mono.texture, (uint8_t *)xor, true);
break;

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -76,7 +76,8 @@ bool egl_damageInit(EGL_Damage ** damage)
if (!egl_shaderCompile((*damage)->shader,
b_shader_damage_vert, b_shader_damage_vert_size,
b_shader_damage_frag, b_shader_damage_frag_size))
b_shader_damage_frag, b_shader_damage_frag_size,
false, NULL))
{
DEBUG_ERROR("Failed to compile the damage shader");
return false;

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -46,9 +46,14 @@ struct DesktopShader
EGL_Shader * shader;
GLint uTransform;
GLint uDesktopSize;
GLint uSamplerType;
GLint uScaleAlgo;
GLint uNVGain;
GLint uCBMode;
GLint uIsHDR;
GLint uMapHDRtoSDR;
GLint uMapHDRGain;
GLint uMapHDRPQ;
};
struct EGL_Desktop
@@ -57,12 +62,14 @@ struct EGL_Desktop
EGLDisplay * display;
EGL_Texture * texture;
struct DesktopShader shader;
struct DesktopShader dmaShader, shader;
EGL_DesktopRects * mesh;
CountedBuffer * matrix;
// internals
int width, height;
bool hdr;
bool hdrPQ;
LG_RendererRotate rotate;
bool useSpice;
@@ -82,6 +89,11 @@ struct EGL_Desktop
bool useDMA;
LG_RendererFormat format;
// map HDR content to SDR
bool mapHDRtoSDR;
int peakLuminance;
int maxCLL;
EGL_PostProcess * pp;
_Atomic(bool) processFrame;
};
@@ -92,7 +104,8 @@ void toggleNV(int key, void * opaque);
static bool egl_initDesktopShader(
struct DesktopShader * shader,
const char * vertex_code , size_t vertex_size,
const char * fragment_code, size_t fragment_size
const char * fragment_code, size_t fragment_size,
bool useDMA
)
{
if (!egl_shaderInit(&shader->shader))
@@ -100,16 +113,21 @@ static bool egl_initDesktopShader(
if (!egl_shaderCompile(shader->shader,
vertex_code , vertex_size,
fragment_code, fragment_size))
fragment_code, fragment_size,
useDMA, NULL))
{
return false;
}
shader->uTransform = egl_shaderGetUniform(shader->shader, "transform" );
shader->uDesktopSize = egl_shaderGetUniform(shader->shader, "desktopSize");
shader->uScaleAlgo = egl_shaderGetUniform(shader->shader, "scaleAlgo" );
shader->uNVGain = egl_shaderGetUniform(shader->shader, "nvGain" );
shader->uCBMode = egl_shaderGetUniform(shader->shader, "cbMode" );
shader->uDesktopSize = egl_shaderGetUniform(shader->shader, "desktopSize" );
shader->uTransform = egl_shaderGetUniform(shader->shader, "transform" );
shader->uScaleAlgo = egl_shaderGetUniform(shader->shader, "scaleAlgo" );
shader->uNVGain = egl_shaderGetUniform(shader->shader, "nvGain" );
shader->uCBMode = egl_shaderGetUniform(shader->shader, "cbMode" );
shader->uIsHDR = egl_shaderGetUniform(shader->shader, "isHDR" );
shader->uMapHDRtoSDR = egl_shaderGetUniform(shader->shader, "mapHDRtoSDR" );
shader->uMapHDRGain = egl_shaderGetUniform(shader->shader, "mapHDRGain" );
shader->uMapHDRPQ = egl_shaderGetUniform(shader->shader, "mapHDRPQ" );
return true;
}
@@ -135,15 +153,6 @@ bool egl_desktopInit(EGL * egl, EGL_Desktop ** desktop_, EGLDisplay * display,
return false;
}
if (!egl_initDesktopShader(
&desktop->shader,
b_shader_desktop_vert , b_shader_desktop_vert_size,
b_shader_desktop_rgb_frag, b_shader_desktop_rgb_frag_size))
{
DEBUG_ERROR("Failed to initialize the generic desktop shader");
return false;
}
if (!egl_desktopRectsInit(&desktop->mesh, maxRects))
{
DEBUG_ERROR("Failed to initialize the desktop mesh");
@@ -157,6 +166,27 @@ bool egl_desktopInit(EGL * egl, EGL_Desktop ** desktop_, EGLDisplay * display,
return false;
}
if (!egl_initDesktopShader(
&desktop->shader,
b_shader_desktop_vert , b_shader_desktop_vert_size,
b_shader_desktop_rgb_frag, b_shader_desktop_rgb_frag_size,
false))
{
DEBUG_ERROR("Failed to initialize the desktop shader");
return false;
}
if (useDMA)
if (!egl_initDesktopShader(
&desktop->dmaShader,
b_shader_desktop_vert , b_shader_desktop_vert_size,
b_shader_desktop_rgb_frag, b_shader_desktop_rgb_frag_size,
true))
{
DEBUG_ERROR("Failed to initialize the desktop DMA shader");
return false;
}
app_registerKeybind(0, 'N', toggleNV, desktop,
"Toggle night vision mode");
@@ -166,12 +196,19 @@ bool egl_desktopInit(EGL * egl, EGL_Desktop ** desktop_, EGLDisplay * display,
desktop->scaleAlgo = option_get_int("egl", "scale" );
desktop->useDMA = useDMA;
desktop->mapHDRtoSDR = option_get_bool("egl", "mapHDRtoSDR" );
desktop->peakLuminance = option_get_int ("egl", "peakLuminance");
desktop->maxCLL = option_get_int ("egl", "maxCLL" );
if (!egl_postProcessInit(&desktop->pp))
{
DEBUG_ERROR("Failed to initialize the post process manager");
return false;
}
// this MUST be first
egl_postProcessAdd(desktop->pp, &egl_filter24bitOps);
egl_postProcessAdd(desktop->pp, &egl_filterDownscaleOps);
egl_postProcessAdd(desktop->pp, &egl_filterFFXCASOps );
egl_postProcessAdd(desktop->pp, &egl_filterFFXFSR1Ops );
@@ -205,11 +242,12 @@ void egl_desktopFree(EGL_Desktop ** desktop)
if (!*desktop)
return;
egl_textureFree (&(*desktop)->texture );
egl_textureFree (&(*desktop)->spiceTexture );
egl_shaderFree (&(*desktop)->shader.shader);
egl_desktopRectsFree(&(*desktop)->mesh );
countedBufferRelease(&(*desktop)->matrix );
egl_textureFree (&(*desktop)->texture );
egl_textureFree (&(*desktop)->spiceTexture );
egl_shaderFree (&(*desktop)->shader .shader);
egl_shaderFree (&(*desktop)->dmaShader.shader);
egl_desktopRectsFree(&(*desktop)->mesh );
countedBufferRelease(&(*desktop)->matrix );
egl_postProcessFree(&(*desktop)->pp);
@@ -255,6 +293,28 @@ void egl_desktopConfigUI(EGL_Desktop * desktop)
}
igSliderInt("##nvgain", &desktop->nvGain, 0, desktop->nvMax, format, 0);
igPopItemWidth();
bool mapHDRtoSDR = desktop->mapHDRtoSDR;
int peakLuminance = desktop->peakLuminance;
int maxCLL = desktop->maxCLL;
igSeparator();
igCheckbox("Map HDR content to SDR", &mapHDRtoSDR);
igSliderInt("Peak Luminance", &peakLuminance, 1, 10000,
"%d nits",
ImGuiInputTextFlags_CharsDecimal);
igSliderInt("Max content light level", &maxCLL, 1, 10000,
"%d nits", ImGuiInputTextFlags_CharsDecimal);
if (mapHDRtoSDR != desktop->mapHDRtoSDR ||
peakLuminance != desktop->peakLuminance ||
maxCLL != desktop->maxCLL)
{
desktop->mapHDRtoSDR = mapHDRtoSDR;
desktop->peakLuminance = max(1, peakLuminance);
desktop->maxCLL = max(1, maxCLL);
app_invalidateWindow(true);
}
}
bool egl_desktopSetup(EGL_Desktop * desktop, const LG_RendererFormat format)
@@ -280,6 +340,19 @@ bool egl_desktopSetup(EGL_Desktop * desktop, const LG_RendererFormat format)
pixFmt = EGL_PF_RGBA16F;
break;
case FRAME_TYPE_BGR_32:
pixFmt = EGL_PF_BGR_32;
break;
case FRAME_TYPE_RGB_24:
pixFmt = EGL_PF_RGB_24;
// the data width is correct per the format, but we are going to use a
// 32-bit texture to load the data, so we need to alter the width for the
// different bpp
desktop->format.dataWidth =
desktop->format.pitch / 4;
break;
default:
DEBUG_ERROR("Unsupported frame format");
return false;
@@ -287,13 +360,16 @@ bool egl_desktopSetup(EGL_Desktop * desktop, const LG_RendererFormat format)
desktop->width = format.frameWidth;
desktop->height = format.frameHeight;
desktop->hdr = format.hdr;
desktop->hdrPQ = format.hdrPQ;
if (!egl_textureSetup(
desktop->texture,
pixFmt,
format.frameWidth,
format.frameHeight,
format.pitch
desktop->format.dataWidth,
desktop->format.dataHeight,
desktop->format.stride,
desktop->format.pitch
))
{
DEBUG_ERROR("Failed to setup the desktop texture");
@@ -399,18 +475,17 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth,
if (atomic_exchange(&desktop->processFrame, false) ||
egl_postProcessConfigModified(desktop->pp))
egl_postProcessRun(desktop->pp, tex, desktop->mesh,
width, height, outputWidth, outputHeight);
width, height, outputWidth, outputHeight, desktop->useDMA);
unsigned int finalSizeX, finalSizeY;
GLuint texture = egl_postProcessGetOutput(desktop->pp,
EGL_Texture * texture = egl_postProcessGetOutput(desktop->pp,
&finalSizeX, &finalSizeY);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
egl_resetViewport(desktop->egl);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glBindSampler(0, tex->sampler);
egl_textureBind(texture);
if (finalSizeX > width || finalSizeY > height)
scaleType = EGL_DESKTOP_DOWNSCALE;
@@ -435,7 +510,13 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth,
scaleAlgo = desktop->scaleAlgo;
}
const struct DesktopShader * shader = &desktop->shader;
const struct DesktopShader * shader =
desktop->useDMA && texture == desktop->texture ?
&desktop->dmaShader : &desktop->shader;
const float mapHDRGain =
desktop->maxCLL / desktop->peakLuminance;
EGL_Uniform uniforms[] =
{
{
@@ -463,6 +544,26 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth,
.type = EGL_UNIFORM_TYPE_1I,
.location = shader->uCBMode,
.f = { desktop->cbMode }
},
{
.type = EGL_UNIFORM_TYPE_1I,
.location = shader->uIsHDR,
.i = { desktop->hdr }
},
{
.type = EGL_UNIFORM_TYPE_1I,
.location = shader->uMapHDRtoSDR,
.i = { desktop->mapHDRtoSDR }
},
{
.type = EGL_UNIFORM_TYPE_1F,
.location = shader->uMapHDRGain,
.f = { mapHDRGain }
},
{
.type = EGL_UNIFORM_TYPE_1I,
.location = shader->uMapHDRPQ,
.f = { desktop->hdrPQ }
}
};
@@ -488,6 +589,7 @@ void egl_desktopSpiceConfigure(EGL_Desktop * desktop, int width, int height)
EGL_PF_BGRA,
width,
height,
width,
width * 4
))
{
@@ -511,7 +613,7 @@ void egl_desktopSpiceDrawFill(EGL_Desktop * desktop, int x, int y, int width,
for(; y < height; ++y)
egl_textureUpdateRect(desktop->spiceTexture,
x, y, width, 1, sizeof(line), (uint8_t *)line, false);
x, y, width, 1, width, sizeof(line), (uint8_t *)line, false);
atomic_store(&desktop->processFrame, true);
}
@@ -520,7 +622,7 @@ void egl_desktopSpiceDrawBitmap(EGL_Desktop * desktop, int x, int y, int width,
int height, int stride, uint8_t * data, bool topDown)
{
egl_textureUpdateRect(desktop->spiceTexture,
x, y, width, height, stride, data, topDown);
x, y, width, height, width, stride, data, topDown);
atomic_store(&desktop->processFrame, true);
}

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -202,6 +202,27 @@ static struct Option egl_options[] =
.type = OPTION_TYPE_BOOL,
.value.x_bool = true
},
{
.module = "egl",
.name = "mapHDRtoSDR",
.description = "Map HDR content to the SDR color space",
.type = OPTION_TYPE_BOOL,
.value.x_bool = true
},
{
.module = "egl",
.name = "peakLuminance",
.description = "The peak luminance level in nits for HDR to SDR mapping",
.type = OPTION_TYPE_INT,
.value.x_int = 250,
},
{
.module = "egl",
.name = "maxCLL",
.description = "Maximum content light level in nits for HDR to SDR mapping",
.type = OPTION_TYPE_INT,
.value.x_int = 10000,
},
{0}
};
@@ -748,7 +769,7 @@ static bool egl_renderStartup(LG_Renderer * renderer, bool useDMA)
EGLint attr[] =
{
EGL_BUFFER_SIZE , 24,
EGL_BUFFER_SIZE , 30,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_SAMPLE_BUFFERS , maxSamples > 0 ? 1 : 0,
EGL_SAMPLES , maxSamples,

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -37,7 +37,9 @@ typedef enum EGL_PixelFormat
EGL_PF_RGBA,
EGL_PF_BGRA,
EGL_PF_RGBA10,
EGL_PF_RGBA16F
EGL_PF_RGBA16F,
EGL_PF_BGR_32,
EGL_PF_RGB_24
}
EGL_PixelFormat;
@@ -60,13 +62,17 @@ typedef struct EGL_TexSetup
/* the height of the texture in pixels */
size_t height;
/* the stide of the texture in bytes */
/* the row length of the texture in pixels */
size_t stride;
/* the row length of the texture in bytes */
size_t pitch;
}
EGL_TexSetup;
typedef enum EGL_FilterType
{
EGL_FILTER_TYPE_INTERNAL,
EGL_FILTER_TYPE_EFFECT,
EGL_FILTER_TYPE_UPSCALE,
EGL_FILTER_TYPE_DOWNSCALE

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -68,9 +68,12 @@ typedef struct EGL_FilterOps
/* reads filter state from options */
void (*loadState)(EGL_Filter * filter);
/* set the input format of the filter */
/* set the input format of the filter
* useDMA will be true if the texture provided needs to use samplerExternalOES
*/
bool (*setup)(EGL_Filter * filter, enum EGL_PixelFormat pixFmt,
unsigned int width, unsigned int height);
unsigned int width, unsigned int height,
unsigned int desktopWidth, unsigned int desktopHeight, bool useDMA);
/* set the output resolution hint for the filter
* this is optional and only a hint */
@@ -87,8 +90,8 @@ typedef struct EGL_FilterOps
/* runs the filter on the provided texture
* returns the processed texture as the output */
GLuint (*run)(EGL_Filter * filter, EGL_FilterRects * rects,
GLuint texture);
EGL_Texture * (*run)(EGL_Filter * filter, EGL_FilterRects * rects,
EGL_Texture * texture);
/* called when the filter output is no loger needed so it can release memory
* this is optional */
@@ -102,6 +105,12 @@ typedef struct EGL_Filter
}
EGL_Filter;
static inline void egl_filterEarlyInit(const EGL_FilterOps * ops)
{
if (ops->earlyInit)
ops->earlyInit();
}
static inline bool egl_filterInit(const EGL_FilterOps * ops, EGL_Filter ** filter)
{
if (!ops->init(filter))
@@ -119,23 +128,30 @@ static inline void egl_filterFree(EGL_Filter ** filter)
static inline bool egl_filterImguiConfig(EGL_Filter * filter)
{
return filter->ops.imguiConfig(filter);
if (filter->ops.imguiConfig)
return filter->ops.imguiConfig(filter);
return false;
}
static inline void egl_filterSaveState(EGL_Filter * filter)
{
filter->ops.saveState(filter);
if (filter->ops.saveState)
filter->ops.saveState(filter);
}
static inline void egl_filterLoadState(EGL_Filter * filter)
{
filter->ops.loadState(filter);
if (filter->ops.loadState)
filter->ops.loadState(filter);
}
static inline bool egl_filterSetup(EGL_Filter * filter,
enum EGL_PixelFormat pixFmt, unsigned int width, unsigned int height)
enum EGL_PixelFormat pixFmt, unsigned int width, unsigned int height,
unsigned int desktopWidth, unsigned int desktopHeight,
bool useDMA)
{
return filter->ops.setup(filter, pixFmt, width, height);
return filter->ops.setup(filter, pixFmt, width, height,
desktopWidth, desktopHeight, useDMA);
}
static inline void egl_filterSetOutputResHint(EGL_Filter * filter,
@@ -156,8 +172,8 @@ static inline bool egl_filterPrepare(EGL_Filter * filter)
return filter->ops.prepare(filter);
}
static inline GLuint egl_filterRun(EGL_Filter * filter,
EGL_FilterRects * rects, GLuint texture)
static inline EGL_Texture * egl_filterRun(EGL_Filter * filter,
EGL_FilterRects * rects, EGL_Texture * texture)
{
return filter->ops.run(filter, rects, texture);
}

View File

@@ -0,0 +1,220 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 59
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "filter.h"
#include "framebuffer.h"
#include <math.h>
#include "common/array.h"
#include "common/debug.h"
#include "common/option.h"
#include "cimgui.h"
#include "basic.vert.h"
#include "convert_24bit.frag.h"
typedef struct EGL_Filter24bit
{
EGL_Filter base;
bool enable;
EGL_PixelFormat format;
int useDMA;
unsigned int width, height;
unsigned int desktopWidth, desktopHeight;
bool prepared;
EGL_Uniform uOutputSize;
EGL_Shader * shader;
EGL_Framebuffer * fb;
GLuint sampler[2];
}
EGL_Filter24bit;
static bool egl_filter24bitInit(EGL_Filter ** filter)
{
EGL_Filter24bit * this = calloc(1, sizeof(*this));
if (!this)
{
DEBUG_ERROR("Failed to allocate ram");
return false;
}
this->useDMA = -1;
if (!egl_shaderInit(&this->shader))
{
DEBUG_ERROR("Failed to initialize the shader");
goto error_this;
}
if (!egl_framebufferInit(&this->fb))
{
DEBUG_ERROR("Failed to initialize the framebuffer");
goto error_shader;
}
glGenSamplers(ARRAY_LENGTH(this->sampler), this->sampler);
glSamplerParameteri(this->sampler[0], GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glSamplerParameteri(this->sampler[0], GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glSamplerParameteri(this->sampler[0], GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE);
glSamplerParameteri(this->sampler[0], GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE);
glSamplerParameteri(this->sampler[1], GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glSamplerParameteri(this->sampler[1], GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glSamplerParameteri(this->sampler[1], GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE);
glSamplerParameteri(this->sampler[1], GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE);
*filter = &this->base;
return true;
error_shader:
egl_shaderFree(&this->shader);
error_this:
free(this);
return false;
}
static void egl_filter24bitFree(EGL_Filter * filter)
{
EGL_Filter24bit * this = UPCAST(EGL_Filter24bit, filter);
egl_shaderFree(&this->shader);
egl_framebufferFree(&this->fb);
glDeleteSamplers(ARRAY_LENGTH(this->sampler), this->sampler);
free(this);
}
static bool egl_filter24bitSetup(EGL_Filter * filter,
enum EGL_PixelFormat pixFmt, unsigned int width, unsigned int height,
unsigned int desktopWidth, unsigned int desktopHeight,
bool useDMA)
{
EGL_Filter24bit * this = UPCAST(EGL_Filter24bit, filter);
if (pixFmt != EGL_PF_BGR_32 && pixFmt != EGL_PF_RGB_24)
return false;
if (this->useDMA != useDMA || this->format != pixFmt)
{
EGL_ShaderDefine defines[] =
{
{"OUTPUT", pixFmt == EGL_PF_BGR_32 ? "fragColor.bgra" : "fragColor.rgba" },
{0}
};
if (!egl_shaderCompile(this->shader,
b_shader_basic_vert , b_shader_basic_vert_size,
b_shader_convert_24bit_frag, b_shader_convert_24bit_frag_size,
useDMA, defines)
)
{
DEBUG_ERROR("Failed to compile the shader");
return false;
}
this->uOutputSize.type = EGL_UNIFORM_TYPE_2F;
this->uOutputSize.location =
egl_shaderGetUniform(this->shader, "outputSize");
this->useDMA = useDMA;
this->prepared = false;
}
if (this->prepared &&
this->width == width &&
this->height == height &&
this->desktopWidth == desktopWidth &&
this->desktopHeight == desktopHeight)
return true;
if (!egl_framebufferSetup(this->fb, pixFmt, desktopWidth, desktopHeight))
return false;
this->format = pixFmt;
this->width = width;
this->height = height;
this->desktopWidth = desktopWidth;
this->desktopHeight = desktopHeight;
this->prepared = false;
return true;
}
static void egl_filter24bitGetOutputRes(EGL_Filter * filter,
unsigned int *width, unsigned int *height)
{
EGL_Filter24bit * this = UPCAST(EGL_Filter24bit, filter);
*width = this->desktopWidth;
*height = this->desktopHeight;
}
static bool egl_filter24bitPrepare(EGL_Filter * filter)
{
EGL_Filter24bit * this = UPCAST(EGL_Filter24bit, filter);
if (this->prepared)
return true;
this->uOutputSize.f[0] = this->desktopWidth;
this->uOutputSize.f[1] = this->desktopHeight;
egl_shaderSetUniforms(this->shader, &this->uOutputSize, 1);
this->prepared = true;
return true;
}
static EGL_Texture * egl_filter24bitRun(EGL_Filter * filter,
EGL_FilterRects * rects, EGL_Texture * texture)
{
EGL_Filter24bit * this = UPCAST(EGL_Filter24bit, filter);
egl_framebufferBind(this->fb);
glActiveTexture(GL_TEXTURE0);
egl_textureBind(texture);
glBindSampler(0, this->sampler[0]);
egl_shaderUse(this->shader);
egl_filterRectsRender(this->shader, rects);
return egl_framebufferGetTexture(this->fb);
}
EGL_FilterOps egl_filter24bitOps =
{
.id = "24bit",
.name = "24bit",
.type = EGL_FILTER_TYPE_INTERNAL,
.earlyInit = NULL,
.init = egl_filter24bitInit,
.free = egl_filter24bitFree,
.imguiConfig = NULL,
.saveState = NULL,
.loadState = NULL,
.setup = egl_filter24bitSetup,
.getOutputRes = egl_filter24bitGetOutputRes,
.prepare = egl_filter24bitPrepare,
.run = egl_filter24bitRun
};

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -60,6 +60,7 @@ typedef struct EGL_FilterDownscale
EGL_Shader * lanczos2;
DownscaleFilter filter;
int useDMA;
enum EGL_PixelFormat pixFmt;
unsigned int width, height;
float pixelSize;
@@ -157,55 +158,26 @@ static bool egl_filterDownscaleInit(EGL_Filter ** filter)
return false;
}
this->useDMA = -1;
if (!egl_shaderInit(&this->nearest))
{
DEBUG_ERROR("Failed to initialize the shader");
goto error_this;
}
if (!egl_shaderCompile(this->nearest,
b_shader_basic_vert , b_shader_basic_vert_size,
b_shader_downscale_frag, b_shader_downscale_frag_size)
)
{
DEBUG_ERROR("Failed to compile the shader");
goto error_shader;
}
if (!egl_shaderInit(&this->linear))
{
DEBUG_ERROR("Failed to initialize the shader");
goto error_this;
}
if (!egl_shaderCompile(this->linear,
b_shader_basic_vert, b_shader_basic_vert_size,
b_shader_downscale_linear_frag, b_shader_downscale_linear_frag_size)
)
{
DEBUG_ERROR("Failed to compile the shader");
goto error_shader;
}
if (!egl_shaderInit(&this->lanczos2))
{
DEBUG_ERROR("Failed to initialize the shader");
goto error_this;
}
if (!egl_shaderCompile(this->lanczos2,
b_shader_basic_vert, b_shader_basic_vert_size,
b_shader_downscale_lanczos2_frag, b_shader_downscale_lanczos2_frag_size)
)
{
DEBUG_ERROR("Failed to compile the shader");
goto error_shader;
}
this->uNearest.type = EGL_UNIFORM_TYPE_3F;
this->uNearest.location =
egl_shaderGetUniform(this->nearest, "uConfig");
if (!egl_framebufferInit(&this->fb))
{
DEBUG_ERROR("Failed to initialize the framebuffer");
@@ -326,7 +298,9 @@ static bool egl_filterDownscaleImguiConfig(EGL_Filter * filter)
}
static bool egl_filterDownscaleSetup(EGL_Filter * filter,
enum EGL_PixelFormat pixFmt, unsigned int width, unsigned int height)
enum EGL_PixelFormat pixFmt, unsigned int width, unsigned int height,
unsigned int desktopWidth, unsigned int desktopHeight,
bool useDMA)
{
EGL_FilterDownscale * this = UPCAST(EGL_FilterDownscale, filter);
@@ -336,6 +310,48 @@ static bool egl_filterDownscaleSetup(EGL_Filter * filter,
if (!this->enable)
return false;
if (this->useDMA != useDMA)
{
if (!egl_shaderCompile(this->nearest,
b_shader_basic_vert , b_shader_basic_vert_size,
b_shader_downscale_frag,
b_shader_downscale_frag_size,
useDMA, NULL)
)
{
DEBUG_ERROR("Failed to compile the shader");
return false;
}
if (!egl_shaderCompile(this->linear,
b_shader_basic_vert, b_shader_basic_vert_size,
b_shader_downscale_linear_frag,
b_shader_downscale_linear_frag_size,
useDMA, NULL)
)
{
DEBUG_ERROR("Failed to compile the shader");
return false;
}
if (!egl_shaderCompile(this->lanczos2,
b_shader_basic_vert, b_shader_basic_vert_size,
b_shader_downscale_lanczos2_frag,
b_shader_downscale_lanczos2_frag_size,
useDMA, NULL)
)
{
DEBUG_ERROR("Failed to compile the shader");
return false;
}
this->uNearest.type = EGL_UNIFORM_TYPE_3F;
this->uNearest.location =
egl_shaderGetUniform(this->nearest, "uConfig");
this->useDMA = useDMA;
}
if (this->prepared &&
pixFmt == this->pixFmt &&
this->width == width &&
@@ -385,15 +401,15 @@ static bool egl_filterDownscalePrepare(EGL_Filter * filter)
return true;
}
static GLuint egl_filterDownscaleRun(EGL_Filter * filter,
EGL_FilterRects * rects, GLuint texture)
static EGL_Texture * egl_filterDownscaleRun(EGL_Filter * filter,
EGL_FilterRects * rects, EGL_Texture * texture)
{
EGL_FilterDownscale * this = UPCAST(EGL_FilterDownscale, filter);
egl_framebufferBind(this->fb);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
egl_textureBind(texture);
EGL_Shader * shader;

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -37,6 +37,7 @@ typedef struct EGL_FilterFFXCAS
EGL_Shader * shader;
bool enable;
int useDMA;
enum EGL_PixelFormat pixFmt;
unsigned int width, height;
float sharpness;
@@ -106,21 +107,14 @@ static bool egl_filterFFXCASInit(EGL_Filter ** filter)
return false;
}
this->useDMA = -1;
if (!egl_shaderInit(&this->shader))
{
DEBUG_ERROR("Failed to initialize the shader");
goto error_this;
}
if (!egl_shaderCompile(this->shader,
b_shader_basic_vert , b_shader_basic_vert_size,
b_shader_ffx_cas_frag, b_shader_ffx_cas_frag_size)
)
{
DEBUG_ERROR("Failed to compile the shader");
goto error_shader;
}
this->consts = countedBufferNew(8 * sizeof(GLuint));
if (!this->consts)
{
@@ -128,12 +122,6 @@ static bool egl_filterFFXCASInit(EGL_Filter ** filter)
goto error_shader;
}
egl_shaderSetUniforms(this->shader, &(EGL_Uniform) {
.type = EGL_UNIFORM_TYPE_4UIV,
.location = egl_shaderGetUniform(this->shader, "uConsts"),
.v = this->consts,
}, 1);
egl_filterFFXCASLoadState(&this->base);
if (!egl_framebufferInit(&this->fb))
@@ -220,13 +208,36 @@ static bool egl_filterFFXCASImguiConfig(EGL_Filter * filter)
}
static bool egl_filterFFXCASSetup(EGL_Filter * filter,
enum EGL_PixelFormat pixFmt, unsigned int width, unsigned int height)
enum EGL_PixelFormat pixFmt, unsigned int width, unsigned int height,
unsigned int desktopWidth, unsigned int desktopHeight,
bool useDMA)
{
EGL_FilterFFXCAS * this = UPCAST(EGL_FilterFFXCAS, filter);
if (!this->enable)
return false;
if (this->useDMA != useDMA)
{
if (!egl_shaderCompile(this->shader,
b_shader_basic_vert , b_shader_basic_vert_size,
b_shader_ffx_cas_frag, b_shader_ffx_cas_frag_size,
useDMA, NULL)
)
{
DEBUG_ERROR("Failed to compile the shader");
return false;
}
egl_shaderSetUniforms(this->shader, &(EGL_Uniform) {
.type = EGL_UNIFORM_TYPE_4UIV,
.location = egl_shaderGetUniform(this->shader, "uConsts"),
.v = this->consts,
}, 1);
this->useDMA = useDMA;
}
if (pixFmt == this->pixFmt && this->width == width && this->height == height)
return true;
@@ -262,15 +273,15 @@ static bool egl_filterFFXCASPrepare(EGL_Filter * filter)
return true;
}
static GLuint egl_filterFFXCASRun(EGL_Filter * filter,
EGL_FilterRects * rects, GLuint texture)
static EGL_Texture * egl_filterFFXCASRun(EGL_Filter * filter,
EGL_FilterRects * rects, EGL_Texture * texture)
{
EGL_FilterFFXCAS * this = UPCAST(EGL_FilterFFXCAS, filter);
egl_framebufferBind(this->fb);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
egl_textureBind(texture);
glBindSampler(0, this->sampler);
egl_shaderUse(this->shader);

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -42,6 +42,7 @@ typedef struct EGL_FilterFFXFSR1
CountedBuffer * consts;
EGL_Uniform easuUniform[2], rcasUniform;
int useDMA;
enum EGL_PixelFormat pixFmt;
unsigned int width, height;
unsigned int inWidth, inHeight;
@@ -109,6 +110,8 @@ static bool egl_filterFFXFSR1Init(EGL_Filter ** filter)
return false;
}
this->useDMA = -1;
if (!egl_shaderInit(&this->easu))
{
DEBUG_ERROR("Failed to initialize the Easu shader");
@@ -121,18 +124,10 @@ static bool egl_filterFFXFSR1Init(EGL_Filter ** filter)
goto error_esau;
}
if (!egl_shaderCompile(this->easu,
b_shader_basic_vert , b_shader_basic_vert_size,
b_shader_ffx_fsr1_easu_frag, b_shader_ffx_fsr1_easu_frag_size)
)
{
DEBUG_ERROR("Failed to compile the Easu shader");
goto error_rcas;
}
if (!egl_shaderCompile(this->rcas,
b_shader_basic_vert , b_shader_basic_vert_size,
b_shader_ffx_fsr1_rcas_frag, b_shader_ffx_fsr1_rcas_frag_size)
b_shader_ffx_fsr1_rcas_frag, b_shader_ffx_fsr1_rcas_frag_size,
false, NULL)
)
{
DEBUG_ERROR("Failed to compile the Rcas shader");
@@ -148,14 +143,6 @@ static bool egl_filterFFXFSR1Init(EGL_Filter ** filter)
egl_filterFFXFSR1LoadState(&this->base);
this->easuUniform[0].type = EGL_UNIFORM_TYPE_4UIV;
this->easuUniform[0].location =
egl_shaderGetUniform(this->easu, "uConsts");
this->easuUniform[0].v = this->consts;
this->easuUniform[1].type = EGL_UNIFORM_TYPE_2F;
this->easuUniform[1].location =
egl_shaderGetUniform(this->easu, "uOutRes");
this->rcasUniform.type = EGL_UNIFORM_TYPE_4UI;
this->rcasUniform.location = egl_shaderGetUniform(this->rcas, "uConsts");
rcasUpdateUniform(this);
@@ -335,13 +322,38 @@ static void egl_filterFFXFSR1SetOutputResHint(EGL_Filter * filter,
}
static bool egl_filterFFXFSR1Setup(EGL_Filter * filter,
enum EGL_PixelFormat pixFmt, unsigned int width, unsigned int height)
enum EGL_PixelFormat pixFmt, unsigned int width, unsigned int height,
unsigned int desktopWidth, unsigned int desktopHeight,
bool useDMA)
{
EGL_FilterFFXFSR1 * this = UPCAST(EGL_FilterFFXFSR1, filter);
if (!this->enable)
return false;
if (this->useDMA != useDMA)
{
if (!egl_shaderCompile(this->easu,
b_shader_basic_vert , b_shader_basic_vert_size,
b_shader_ffx_fsr1_easu_frag, b_shader_ffx_fsr1_easu_frag_size,
useDMA, NULL)
)
{
DEBUG_ERROR("Failed to compile the Easu shader");
return false;
}
this->easuUniform[0].type = EGL_UNIFORM_TYPE_4UIV;
this->easuUniform[0].location =
egl_shaderGetUniform(this->easu, "uConsts");
this->easuUniform[0].v = this->consts;
this->easuUniform[1].type = EGL_UNIFORM_TYPE_2F;
this->easuUniform[1].location =
egl_shaderGetUniform(this->easu, "uOutRes");
this->useDMA = useDMA;
}
this->active = this->width > width && this->height > height;
if (!this->active)
return false;
@@ -395,15 +407,15 @@ static bool egl_filterFFXFSR1Prepare(EGL_Filter * filter)
return true;
}
static GLuint egl_filterFFXFSR1Run(EGL_Filter * filter,
EGL_FilterRects * rects, GLuint texture)
static EGL_Texture * egl_filterFFXFSR1Run(EGL_Filter * filter,
EGL_FilterRects * rects, EGL_Texture * texture)
{
EGL_FilterFFXFSR1 * this = UPCAST(EGL_FilterFFXFSR1, filter);
// pass 1, Easu
egl_framebufferBind(this->easuFb);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
egl_textureBind(texture);
glBindSampler(0, this->sampler);
egl_shaderUse(this->easu);
egl_filterRectsRender(this->easu, rects);
@@ -412,7 +424,7 @@ static GLuint egl_filterFFXFSR1Run(EGL_Filter * filter,
// pass 2, Rcas
egl_framebufferBind(this->rcasFb);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
egl_textureBind(texture);
glBindSampler(0, this->sampler);
egl_shaderUse(this->rcas);
egl_filterRectsRender(this->rcas, rects);

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -20,6 +20,7 @@
#pragma once
extern EGL_FilterOps egl_filter24bitOps;
extern EGL_FilterOps egl_filterDownscaleOps;
extern EGL_FilterOps egl_filterFFXCASOps;
extern EGL_FilterOps egl_filterFFXFSR1Ops;

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -64,7 +64,7 @@ void egl_framebufferFree(EGL_Framebuffer ** fb)
bool egl_framebufferSetup(EGL_Framebuffer * this, enum EGL_PixelFormat pixFmt,
unsigned int width, unsigned int height)
{
if (!egl_textureSetup(this->tex, pixFmt, width, height, 0))
if (!egl_textureSetup(this->tex, pixFmt, width, height, 0, 0))
{
DEBUG_ERROR("Failed to setup the texture");
return false;
@@ -100,9 +100,7 @@ void egl_framebufferBind(EGL_Framebuffer * this)
glViewport(0, 0, this->tex->format.width, this->tex->format.height);
}
GLuint egl_framebufferGetTexture(EGL_Framebuffer * this)
EGL_Texture * egl_framebufferGetTexture(EGL_Framebuffer * this)
{
GLuint output;
egl_textureGet(this->tex, &output, NULL, NULL);
return output;
return this->tex;
}

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -32,4 +32,4 @@ bool egl_framebufferSetup(EGL_Framebuffer * this, enum EGL_PixelFormat pixFmt,
void egl_framebufferBind(EGL_Framebuffer * this);
GLuint egl_framebufferGetTexture(EGL_Framebuffer * this);
EGL_Texture * egl_framebufferGetTexture(EGL_Framebuffer * this);

View File

@@ -10,4 +10,4 @@ function process(line, second) {
}
}
{ process($0, $2) }
{ process($0, $2) } END { print "\0"; }

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -48,8 +48,8 @@ static const EGL_FilterOps * EGL_Filters[] =
struct EGL_PostProcess
{
Vector filters;
GLuint output;
Vector filters, internalFilters;
EGL_Texture * output;
unsigned int outputX, outputY;
_Atomic(bool) modified;
@@ -85,7 +85,7 @@ void egl_postProcessEarlyInit(void)
option_register(options);
for (int i = 0; i < ARRAY_LENGTH(EGL_Filters); ++i)
EGL_Filters[i]->earlyInit();
egl_filterEarlyInit(EGL_Filters[i]);
}
static void loadPreset(struct EGL_PostProcess * this, const char * name);
@@ -464,7 +464,8 @@ static void configUI(void * opaque, int * id)
static size_t mouseIdx = -1;
static bool moving = false;
static size_t moveIdx = 0;
bool doMove = false;
bool doMove = false;
ImVec2 window, pos;
igGetWindowPos(&window);
@@ -518,9 +519,16 @@ static void configUI(void * opaque, int * id)
{
EGL_Filter * tmp = filters[moveIdx];
if (mouseIdx > moveIdx) // moving down
memmove(filters + moveIdx, filters + moveIdx + 1, (mouseIdx - moveIdx) * sizeof(EGL_Filter *));
memmove(
filters + moveIdx,
filters + moveIdx + 1,
(mouseIdx - moveIdx) * sizeof(EGL_Filter *));
else // moving up
memmove(filters + mouseIdx + 1, filters + mouseIdx, (moveIdx - mouseIdx) * sizeof(EGL_Filter *));
memmove(
filters + mouseIdx + 1,
filters + mouseIdx,
(moveIdx - mouseIdx) * sizeof(EGL_Filter *));
filters[mouseIdx] = tmp;
}
@@ -540,16 +548,24 @@ bool egl_postProcessInit(EGL_PostProcess ** pp)
return false;
}
if (!vector_create(&this->filters, sizeof(EGL_Filter *), ARRAY_LENGTH(EGL_Filters)))
if (!vector_create(&this->filters,
sizeof(EGL_Filter *), ARRAY_LENGTH(EGL_Filters)))
{
DEBUG_ERROR("Failed to allocate the filter list");
goto error_this;
}
if (!vector_create(&this->internalFilters,
sizeof(EGL_Filter *), ARRAY_LENGTH(EGL_Filters)))
{
DEBUG_ERROR("Failed to allocate the filter list");
goto error_filters;
}
if (!egl_desktopRectsInit(&this->rects, 1))
{
DEBUG_ERROR("Failed to initialize the desktop rects");
goto error_filters;
goto error_internal;
}
loadPresetList(this);
@@ -559,6 +575,9 @@ bool egl_postProcessInit(EGL_PostProcess ** pp)
*pp = this;
return true;
error_internal:
vector_destroy(&this->internalFilters);
error_filters:
vector_destroy(&this->filters);
@@ -579,6 +598,10 @@ void egl_postProcessFree(EGL_PostProcess ** pp)
egl_filterFree(filter);
vector_destroy(&this->filters);
vector_forEachRef(filter, &this->internalFilters)
egl_filterFree(filter);
vector_destroy(&this->internalFilters);
free(this->presetDir);
if (this->presets)
stringlist_free(&this->presets);
@@ -595,7 +618,10 @@ bool egl_postProcessAdd(EGL_PostProcess * this, const EGL_FilterOps * ops)
if (!egl_filterInit(ops, &filter))
return false;
vector_push(&this->filters, &filter);
if (ops->type == EGL_FILTER_TYPE_INTERNAL)
vector_push(&this->internalFilters, &filter);
else
vector_push(&this->filters, &filter);
return true;
}
@@ -606,7 +632,7 @@ bool egl_postProcessConfigModified(EGL_PostProcess * this)
bool egl_postProcessRun(EGL_PostProcess * this, EGL_Texture * tex,
EGL_DesktopRects * rects, int desktopWidth, int desktopHeight,
unsigned int targetX, unsigned int targetY)
unsigned int targetX, unsigned int targetY, bool useDMA)
{
if (targetX == 0 && targetY == 0)
DEBUG_FATAL("targetX || targetY == 0");
@@ -614,8 +640,9 @@ bool egl_postProcessRun(EGL_PostProcess * this, EGL_Texture * tex,
EGL_Filter * lastFilter = NULL;
unsigned int sizeX, sizeY;
GLuint texture;
if (egl_textureGet(tex, &texture, &sizeX, &sizeY) != EGL_TEX_STATUS_OK)
//TODO: clean this up
GLuint _unused;
if (egl_textureGet(tex, &_unused, &sizeX, &sizeY) != EGL_TEX_STATUS_OK)
return false;
if (atomic_exchange(&this->modified, false))
@@ -636,22 +663,36 @@ bool egl_postProcessRun(EGL_PostProcess * this, EGL_Texture * tex,
};
EGL_Filter * filter;
vector_forEach(filter, &this->filters)
EGL_Texture * texture = tex;
const Vector * lists[] =
{
egl_filterSetOutputResHint(filter, targetX, targetY);
&this->internalFilters,
&this->filters,
NULL
};
if (!egl_filterSetup(filter, tex->format.pixFmt, sizeX, sizeY) ||
!egl_filterPrepare(filter))
continue;
for(const Vector ** filters = lists; *filters; ++filters)
vector_forEach(filter, *filters)
{
egl_filterSetOutputResHint(filter, targetX, targetY);
texture = egl_filterRun(filter, &filterRects, texture);
egl_filterGetOutputRes(filter, &sizeX, &sizeY);
if (!egl_filterSetup(filter, tex->format.pixFmt, sizeX, sizeY,
desktopWidth, desktopHeight, useDMA) ||
!egl_filterPrepare(filter))
continue;
if (lastFilter)
egl_filterRelease(lastFilter);
texture = egl_filterRun(filter, &filterRects, texture);
egl_filterGetOutputRes(filter, &sizeX, &sizeY);
lastFilter = filter;
}
if (lastFilter)
egl_filterRelease(lastFilter);
lastFilter = filter;
// the first filter to run will convert to a normal texture
useDMA = false;
}
this->output = texture;
this->outputX = sizeX;
@@ -659,7 +700,7 @@ bool egl_postProcessRun(EGL_PostProcess * this, EGL_Texture * tex,
return true;
}
GLuint egl_postProcessGetOutput(EGL_PostProcess * this,
EGL_Texture * egl_postProcessGetOutput(EGL_PostProcess * this,
unsigned int * outputX, unsigned int * outputY)
{
*outputX = this->outputX;

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -41,7 +41,7 @@ bool egl_postProcessConfigModified(EGL_PostProcess * this);
* targetX/Y is the final target output dimension hint if scalers are present */
bool egl_postProcessRun(EGL_PostProcess * this, EGL_Texture * tex,
EGL_DesktopRects * rects, int desktopWidth, int desktopHeight,
unsigned int targetX, unsigned int targetY);
unsigned int targetX, unsigned int targetY, bool useDMA);
GLuint egl_postProcessGetOutput(EGL_PostProcess * this,
EGL_Texture * egl_postProcessGetOutput(EGL_PostProcess * this,
unsigned int * outputX, unsigned int * outputY);

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -64,7 +64,9 @@ void egl_shaderFree(EGL_Shader ** shader)
*shader = NULL;
}
bool egl_shaderLoad(EGL_Shader * this, const char * vertex_file, const char * fragment_file)
bool egl_shaderLoad(EGL_Shader * this,
const char * vertex_file, const char * fragment_file, bool useDMA,
const EGL_ShaderDefine * defines)
{
char * vertex_code, * fragment_code;
size_t vertex_size, fragment_size;
@@ -86,13 +88,16 @@ bool egl_shaderLoad(EGL_Shader * this, const char * vertex_file, const char * fr
DEBUG_INFO("Loaded fragment shader: %s", fragment_file);
bool ret = egl_shaderCompile(this, vertex_code, vertex_size, fragment_code, fragment_size);
bool ret = egl_shaderCompile(this,
vertex_code, vertex_size, fragment_code, fragment_size,
useDMA, defines);
free(vertex_code);
free(fragment_code);
return ret;
}
bool egl_shaderCompile(EGL_Shader * this, const char * vertex_code,
static bool shaderCompile(EGL_Shader * this, const char * vertex_code,
size_t vertex_size, const char * fragment_code, size_t fragment_size)
{
if (this->hasShader)
@@ -204,6 +209,143 @@ bool egl_shaderCompile(EGL_Shader * this, const char * vertex_code,
return true;
}
bool egl_shaderCompile(EGL_Shader * this, const char * vertex_code,
size_t vertex_size, const char * fragment_code, size_t fragment_size,
bool useDMA, const EGL_ShaderDefine * defines)
{
bool result = false;
char * processed = NULL;
char * newCode = NULL;
if (useDMA)
{
const char * search = "sampler2D";
const char * replace = "samplerExternalOES";
const char * src = fragment_code;
int instances = 0;
while((src = strstr(src, search)))
{
++instances;
src += strlen(search);
}
const int diff = (strlen(replace) - strlen(search)) * instances;
const int newLen = fragment_size + diff;
newCode = malloc(newLen + 1);
if (!newCode)
{
DEBUG_ERROR("Out of memory");
goto exit;
}
src = fragment_code;
char * dst = newCode;
for(int i = 0; i < instances; ++i)
{
const char * pos = strstr(src, search);
const int offset = pos - src;
memcpy(dst, src, offset);
dst += offset;
src = pos + strlen(search);
memcpy(dst, replace, strlen(replace));
dst += strlen(replace);
}
const int final = fragment_size - (src - fragment_code);
memcpy(dst, src, final);
dst[final] = '\0';
fragment_code = newCode;
fragment_size = newLen;
}
if (defines)
{
// find the end of any existing lines starting with #
bool newLine = true;
bool skip = false;
int insertPos = 0;
for(int i = 0; i < fragment_size; ++i)
{
if (skip)
{
if (fragment_code[i] == '\n')
skip = false;
continue;
}
switch(fragment_code[i])
{
case '\n':
newLine = true;
continue;
case ' ':
case '\t':
case '\r':
continue;
case '#':
if (newLine)
{
skip = true;
continue;
}
//fallthrough
default:
newLine = false;
break;
}
if (!newLine)
{
insertPos = i - 1;
break;
}
}
int processedLen = fragment_size;
const char * defineFormat = "#define %s %s\n";
for(const EGL_ShaderDefine * define = defines; define->name; ++define)
processedLen += snprintf(NULL, 0, defineFormat, define->name, define->value);
processed = malloc(processedLen);
if (!processed)
{
DEBUG_ERROR("Out of memory");
goto exit;
}
memcpy(processed, fragment_code, insertPos);
int offset = insertPos;
for(const EGL_ShaderDefine * define = defines; define->name; ++define)
offset += sprintf(processed + offset, defineFormat,
define->name, define->value);
memcpy(
processed + offset,
fragment_code + insertPos,
fragment_size - insertPos);
fragment_code = processed;
fragment_size = processedLen;
}
result = shaderCompile(this,
vertex_code , vertex_size,
fragment_code, fragment_size);
exit:
free(processed);
free(newCode);
return result;
}
void egl_shaderSetUniforms(EGL_Shader * this, EGL_Uniform * uniforms, int count)
{
egl_shaderFreeUniforms(this);

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -93,14 +93,22 @@ typedef struct EGL_Uniform
}
EGL_Uniform;
typedef struct EGL_ShaderDefine
{
const char * name;
const char * value;
}
EGL_ShaderDefine;
bool egl_shaderInit(EGL_Shader ** shader);
void egl_shaderFree(EGL_Shader ** shader);
bool egl_shaderLoad(EGL_Shader * model, const char * vertex_file,
const char * fragment_file);
const char * fragment_file, bool useDMA, const EGL_ShaderDefine * defines);
bool egl_shaderCompile(EGL_Shader * model, const char * vertex_code,
size_t vertex_size, const char * fragment_code, size_t fragment_size);
size_t vertex_size, const char * fragment_code, size_t fragment_size,
bool useDMA, const EGL_ShaderDefine * defines);
void egl_shaderSetUniforms(EGL_Shader * shader, EGL_Uniform * uniforms,
int count);

View File

@@ -1,5 +1,5 @@
#version 300 es
precision mediump float;
precision highp float;
layout(location = 0) in vec2 vertex;
out vec2 fragCoord;

View File

@@ -1,16 +1,21 @@
#if __VERSION__ == 300
vec4 textureGather(sampler2D tex, vec2 uv, int comp)
{
vec4 c0 = textureOffset(tex, uv, ivec2(0,1));
vec4 c1 = textureOffset(tex, uv, ivec2(1,1));
vec4 c2 = textureOffset(tex, uv, ivec2(1,0));
vec4 c3 = textureOffset(tex, uv, ivec2(0,0));
vec2 res = vec2(textureSize(tex, 0));
ivec2 p = ivec2((uv * res) - 0.5f);
// NOTE: we can't use texelFecthOffset because sampler2D may actually be samplerExternalOES
vec4 c0 = texelFetch(tex, p+ivec2(0,1), 0);
vec4 c1 = texelFetch(tex, p+ivec2(1,1), 0);
vec4 c2 = texelFetch(tex, p+ivec2(1,0), 0);
vec4 c3 = texelFetch(tex, p+ivec2(0,0), 0);
return vec4(c0[comp], c1[comp], c2[comp],c3[comp]);
}
#elif __VERSION__ < 300
vec4 textureGather(sampler2D tex, vec2 uv, int comp)
{
vec4 c3 = texture2D(tex, uv);
vec4 c3 = texture(tex, uv);
return vec4(c3[comp], c3[comp], c3[comp],c3[comp]);
}
#endif

View File

@@ -0,0 +1,32 @@
#version 300 es
#extension GL_OES_EGL_image_external_essl3 : enable
precision highp float;
in vec2 fragCoord;
out vec4 fragColor;
uniform sampler2D sampler1;
uniform vec2 outputSize;
void main()
{
uvec2 inputSize = uvec2(textureSize(sampler1, 0));
uvec2 outputPos = uvec2(fragCoord * outputSize);
uint fst = outputPos.x * 3u / 4u;
vec4 color_0 = texelFetch(sampler1, ivec2(fst, outputPos.y), 0);
uint snd = (outputPos.x * 3u + 1u) / 4u;
vec4 color_1 = texelFetch(sampler1, ivec2(snd, outputPos.y), 0);
uint trd = (outputPos.x * 3u + 2u) / 4u;
vec4 color_2 = texelFetch(sampler1, ivec2(trd, outputPos.y), 0);
OUTPUT = vec4(
color_0.barg[outputPos.x % 4u],
color_1.gbar[outputPos.x % 4u],
color_2.rgba[outputPos.x % 4u],
1.0
);
}

View File

@@ -1,5 +1,5 @@
#version 300 es
precision mediump float;
precision highp float;
layout(location = 0) in vec3 vertexPosition_modelspace;
layout(location = 1) in vec2 vertexUV;

View File

@@ -1,5 +1,5 @@
#version 300 es
precision mediump float;
precision highp float;
in vec2 uv;
out vec4 color;

View File

@@ -1,5 +1,5 @@
#version 300 es
precision mediump float;
precision highp float;
#include "color_blind.h"

View File

@@ -1,5 +1,5 @@
#version 300 es
precision mediump float;
precision highp float;
out vec4 color;

View File

@@ -1,5 +1,5 @@
#version 300 es
precision mediump float;
precision highp float;
layout(location = 0) in vec2 vertex;
out vec2 uv;

View File

@@ -1,5 +1,7 @@
#version 300 es
precision mediump float;
#extension GL_OES_EGL_image_external_essl3 : enable
precision highp float;
#define EGL_SCALE_AUTO 0
#define EGL_SCALE_NEAREST 1
@@ -7,6 +9,7 @@ precision mediump float;
#define EGL_SCALE_MAX 3
#include "color_blind.h"
#include "hdr.h"
in vec2 uv;
out vec4 color;
@@ -17,21 +20,32 @@ uniform int scaleAlgo;
uniform float nvGain;
uniform int cbMode;
uniform bool isHDR;
uniform bool mapHDRtoSDR;
uniform float mapHDRGain;
uniform bool mapHDRPQ;
void main()
{
switch (scaleAlgo)
{
case EGL_SCALE_NEAREST:
{
vec2 ts = vec2(textureSize(sampler1, 0));
color = texelFetch(sampler1, ivec2(uv * ts), 0);
break;
}
case EGL_SCALE_LINEAR:
{
color = texture(sampler1, uv);
break;
}
}
if (isHDR && mapHDRtoSDR)
color.rgb = mapToSDR(color.rgb, mapHDRGain, mapHDRPQ);
if (cbMode > 0)
color = cbTransform(color, cbMode);

Some files were not shown because too many files have changed in this diff Show More