Compare commits

...

281 Commits

Author SHA1 Message Date
Geoffrey McRae
27fe47cbe2 [obs] dmabuf: enable dmabuf by default
Some checks are pending
build / client (Debug, map[cc:clang cxx:clang++], libdecor) (push) Waiting to run
build / client (Debug, map[cc:clang cxx:clang++], xdg-shell) (push) Waiting to run
build / client (Debug, map[cc:gcc cxx:g++], libdecor) (push) Waiting to run
build / client (Debug, map[cc:gcc cxx:g++], xdg-shell) (push) Waiting to run
build / client (Release, map[cc:clang cxx:clang++], libdecor) (push) Waiting to run
build / client (Release, map[cc:clang cxx:clang++], xdg-shell) (push) Waiting to run
build / client (Release, map[cc:gcc cxx:g++], libdecor) (push) Waiting to run
build / client (Release, map[cc:gcc cxx:g++], xdg-shell) (push) Waiting to run
build / module (push) Waiting to run
build / host-linux (push) Waiting to run
build / host-windows-cross (push) Waiting to run
build / host-windows-native (push) Waiting to run
build / obs (clang) (push) Waiting to run
build / obs (gcc) (push) Waiting to run
build / docs (push) Waiting to run
2025-03-06 14:39:51 +11:00
Geoffrey McRae
aefbebff9c [obs] cosmetics: adhere to 80 column rule 2025-03-06 14:39:31 +11:00
Geoffrey McRae
9174b1ae0f [host] d12: perform full re-initialization if the heapTest fails
Some checks are pending
build / client (Debug, map[cc:clang cxx:clang++], libdecor) (push) Waiting to run
build / client (Debug, map[cc:clang cxx:clang++], xdg-shell) (push) Waiting to run
build / client (Debug, map[cc:gcc cxx:g++], libdecor) (push) Waiting to run
build / client (Debug, map[cc:gcc cxx:g++], xdg-shell) (push) Waiting to run
build / client (Release, map[cc:clang cxx:clang++], libdecor) (push) Waiting to run
build / client (Release, map[cc:clang cxx:clang++], xdg-shell) (push) Waiting to run
build / client (Release, map[cc:gcc cxx:g++], libdecor) (push) Waiting to run
build / client (Release, map[cc:gcc cxx:g++], xdg-shell) (push) Waiting to run
build / module (push) Waiting to run
build / host-linux (push) Waiting to run
build / host-windows-cross (push) Waiting to run
build / host-windows-native (push) Waiting to run
build / obs (clang) (push) Waiting to run
build / obs (gcc) (push) Waiting to run
build / docs (push) Waiting to run
2025-03-05 16:44:29 +11:00
Geoffrey McRae
f6b7ea11c8 [host] app: fix complation on windows with mingw 2025-03-05 16:34:07 +11:00
Geoffrey McRae
2c50ce4dbd [github] build: add libfontconfig-dev dependency 2025-03-05 16:25:01 +11:00
Geoffrey McRae
f6b0752e45 [github] build: use native packages now ubuntu 24.04 is available 2025-03-05 16:22:00 +11:00
Geoffrey McRae
50fee59b29 [client] app: fix broken keyboard input after imgui update 2025-03-05 16:07:06 +11:00
Geoffrey McRae
554f5bf75d [client] overlay: use graph address as imgui id 2025-03-05 15:25:34 +11:00
Geoffrey McRae
b43f572af0 Revert "[client] overlay/status: don't return damage rect if nothing was drawn"
This reverts commit 7e9e38faa5 as it
causes screen corruption when moving imgui overlay dialogs around.
2025-03-05 15:18:29 +11:00
Geoffrey McRae
d9f2df361d [client] cimgui: update to 1.91.8 2025-03-05 15:16:31 +11:00
Geoffrey McRae
6dcf178879 [github] linux-host: add missing dependency for xcb/shm 2025-03-05 13:32:33 +11:00
Geoffrey McRae
ea00b623ed [github] linux-host: add missing dependency for gio/gio-unix 2025-03-05 13:27:43 +11:00
Geoffrey McRae
711c932380 [all] common: fix compilation on clang 2025-03-05 12:48:20 +11:00
Geoffrey McRae
be52a86a9a [all] repos: update LGMP and PureSpice submodules 2025-03-05 12:44:58 +11:00
Geoffrey McRae
420eaebb71 [cmake] all: update cmake_minimum_required version to 3.10 2025-03-05 12:27:23 +11:00
Geoffrey McRae
551298ed5b [doc] all: update copyright year 2025-03-05 12:24:38 +11:00
Mark Stosberg
41008add12 [client] linux: Install .desktop file and icon
SVGs have had a great support for Linux for about a decade, so only
install that for simplicity.
2025-03-05 11:12:42 +11:00
Jonathan Rubenstein
32d1b8063e [doc] requirements: Modify language of DMABUF for iGPUS 2025-03-05 11:11:54 +11:00
Jonathan Rubenstein
b0227a8ff8 [doc] Add hypervisor and framebuffer to words.txt
Used `python ./sort_words.py -s -a framebuffer -a hypervisor`
This also properly sorted the list
2025-03-05 11:11:54 +11:00
Jonathan Rubenstein
a1c713556d [doc] install_libvirt: Link to iGPUs should use DMABUF 2025-03-05 11:11:54 +11:00
Jonathan Rubenstein
a0cf34df73 [doc] requirements: Add section encouraging DMABUF use for iGPUs 2025-03-05 11:11:54 +11:00
Jonathan Rubenstein
fbb489b9b6 [github] pr-check: Automatically add review requesting changes when PR author is not found in AUTHORS 2025-03-05 11:02:45 +11:00
Chris Spencer
03ca20d3e4 [client] overlay/msg: fix race condition in render
Some checks are pending
build / client (Debug, map[cc:clang cxx:clang++], libdecor) (push) Waiting to run
build / client (Debug, map[cc:clang cxx:clang++], xdg-shell) (push) Waiting to run
build / client (Debug, map[cc:gcc cxx:g++], libdecor) (push) Waiting to run
build / client (Debug, map[cc:gcc cxx:g++], xdg-shell) (push) Waiting to run
build / client (Release, map[cc:clang cxx:clang++], libdecor) (push) Waiting to run
build / client (Release, map[cc:clang cxx:clang++], xdg-shell) (push) Waiting to run
build / client (Release, map[cc:gcc cxx:g++], libdecor) (push) Waiting to run
build / client (Release, map[cc:gcc cxx:g++], xdg-shell) (push) Waiting to run
build / module (push) Waiting to run
build / host-linux (push) Waiting to run
build / host-windows-cross (push) Waiting to run
build / host-windows-native (push) Waiting to run
build / obs (clang) (push) Waiting to run
build / obs (gcc) (push) Waiting to run
build / docs (push) Waiting to run
If an overlay is closed with overlayMsg_close, the message can be freed
while it is still being used by msg_render, resulting in a segfault. Lock
the message list for the duration of msg_render to fix this.
2025-03-05 10:59:05 +11:00
Chris Spencer
7e9e38faa5 [client] overlay/status: don't return damage rect if nothing was drawn
The renderer contains an optimization to skip ImGui if there is nothing to
show, but the status overlay always returns a damage rect, even if it
didn't draw anything, so the optimization can never take effect.
2025-03-05 10:58:10 +11:00
Chris Spencer
0fd6f59bbb [client] egl: fix desktop render dimensions check
Code now matches the error message.
2025-03-05 10:57:20 +11:00
Justin Gatzen
661efd107e [host] app: fix app state race in lgmpTimer thread
While resuming from hibernation lgmpTimer may transition app.state to
APP_STATE_REINIT_LGMP. Sometimes the transition is lost if the app_main
processing loop also changes app.state simultaneously. This seems to
occur frequently with the hibernation use case.

Separate lgmp timer state into its own enum. Move resulting app.state
transitions to the app_main loop so they are serialized.
2025-03-05 10:56:39 +11:00
Jérôme Poulin
f6094de919 [module] MODULE_IMPORT_NS now requires a string literal in 6.13
Fixes: #1155
References: 33def8498fdde180023444b08e12b72a9efed41d
Co-authored-by: HikariKnightt <2557889+HikariKnight@users.noreply.github.com>
Co-authored-by: zeule <zeule@users.noreply.github.com>
Reviewed-by: netboy3 <1472804+netboy3@users.noreply.github.com>
2025-03-05 10:52:31 +11:00
Geoffrey McRae
77f6054f0a d12: implement indirectCopy fallback for compatibillity
When the heapTest fails for DMA copies to shared memory, fallback to
conventional CPU copy via mapped resources. While this is less optimal,
it is still faster then the older DXGI capture backend.
2025-02-19 16:30:27 +11:00
Geoffrey McRae
c169d4ab23 [obs] dmabuf: fix failure to display frames in both buffers 2025-02-14 19:24:36 +11:00
rs189
e25492a3a3 [client] x11/wayland: add application id
Some checks failed
build / client (Debug, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / module (push) Has been cancelled
build / host-linux (push) Has been cancelled
build / host-windows-cross (push) Has been cancelled
build / host-windows-native (push) Has been cancelled
build / obs (clang) (push) Has been cancelled
build / obs (gcc) (push) Has been cancelled
build / docs (push) Has been cancelled
2024-10-15 11:52:10 +11:00
Geoffrey McRae
4e8201da07 [common] ivshmem: default to /dev/kvmfr0 if it's found
Some checks failed
build / client (Debug, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / module (push) Has been cancelled
build / host-linux (push) Has been cancelled
build / host-windows-cross (push) Has been cancelled
build / host-windows-native (push) Has been cancelled
build / obs (clang) (push) Has been cancelled
build / obs (gcc) (push) Has been cancelled
build / docs (push) Has been cancelled
2024-09-05 14:01:28 +10:00
Geoffrey McRae
6a0a635781 [common] rect: fix avx unaligned bytes copy
Some checks failed
build / client (Debug, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / module (push) Has been cancelled
build / host-linux (push) Has been cancelled
build / host-windows-cross (push) Has been cancelled
build / host-windows-native (push) Has been cancelled
build / obs (clang) (push) Has been cancelled
build / obs (gcc) (push) Has been cancelled
build / docs (push) Has been cancelled
Thanks @D0ot for debugging and finding this this, the LG community are
very appreciate for a fix for this long outstanding bug.

Fixes #1129
Closes #1136
2024-08-30 09:12:19 +10:00
Geoffrey McRae
3ea37b86e3 [module] check vmf->pgoff before using it
Some checks failed
build / client (Debug, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / module (push) Has been cancelled
build / host-linux (push) Has been cancelled
build / host-windows-cross (push) Has been cancelled
build / host-windows-native (push) Has been cancelled
build / obs (clang) (push) Has been cancelled
build / obs (gcc) (push) Has been cancelled
build / docs (push) Has been cancelled
As reported by @Crispy-fried-chicken in issue #1133 there is a potential
XXE vulnerability here. This fixes this problem by verifying the value
of `vmf->pgff` does not exceed the bounds of the memory mapping.

Fixes: #1133
2024-08-26 14:37:21 +10:00
Geoffrey McRae
d060e375ea [client] fix typo
Fixes #1122 - Thanks @MadelineRitchie
2024-06-07 19:04:03 +10:00
Geoffrey McRae
7305ce36af [module] fix build on linux 6.10
Fixes #1124 - Thanks @pongo1231
2024-06-07 19:02:23 +10:00
vmfortress
c04f84b85c [client] pipewire: Add pipewire application name 2024-06-07 18:59:14 +10:00
majcosta
d21bdebc52 [doc] kvmfr/libvirt: change double quotes to single quotes
virt-manager (or libvirt itself) tends to preserve outer quotation marks but explode inner double-quotes into '&quot' which is annoying.

this looks nicer when pasted into the XML editor and applied

Also used double-quotes for the QEMU <6.2 example for consistency

PS: added myself to AUTHORS since this is my first contribution
2024-06-02 12:42:13 +10:00
Jacob McNamee
695cbc2d61 [all] update authors 2024-05-20 19:42:21 +10:00
Jacob McNamee
2067b21d47 [client] egl: fix line copy size computation in texBufferStreamUpdate 2024-05-20 19:42:21 +10:00
Jacob McNamee
9bc82ab1b4 [client] egl: fix misuse of stride vs. pitch in texBufferStreamUpdate 2024-05-20 19:42:21 +10:00
Jacob McNamee
82c9df54c5 [client] egl: fix unintended vertical clipping in spiceDrawFill 2024-05-20 19:42:21 +10:00
Jacob McNamee
c48bd35b3a [client] opengl: fix unintended vertical clipping in spiceDrawFill 2024-05-20 19:42:21 +10:00
Geoffrey McRae
ecd3692e1e [host] dxgi: fix crash during init due to out of order accesses 2024-04-04 22:44:49 +11:00
Geoffrey McRae
23b773ad80 [client] wayland: fix failure to select libdecor
Fixes #1116 - Thanks @blu3bird
2024-03-27 01:57:01 +11:00
kamplom
a626a1142d [client] wayland: Let viewporter use full wl_buffer 2024-03-22 03:56:26 +11:00
Netboy3
e70718600c [doc] Update module libvirt setup 2024-03-21 13:00:05 +11:00
Geoffrey McRae
0990c59eff [obs] fix compilation for older versions of OBS 2024-03-18 17:42:40 +11:00
Geoffrey McRae
fb1d96e147 [obs] tell OBS if we are operating in HDR 2024-03-18 17:35:25 +11:00
Geoffrey McRae
7f515c54b3 [client] x11/i3: fix fullscreen at launch via parameter/config 2024-03-14 12:56:39 +11:00
Geoffrey McRae
20972cfd9b [client] cmake: move X11 config directives to displayservers 2024-03-13 11:17:25 +11:00
Geoffrey McRae
dc9065b62f [client] egl: do not use DMA when using the spice display 2024-03-12 13:57:23 +11:00
Geoffrey McRae
13b9756e80 [client] egl: fix desktop spice toggle race 2024-03-12 11:58:16 +11:00
Geoffrey McRae
d902afa3dc [host] d12: fix error output string format 2024-03-11 20:32:34 +11:00
Geoffrey McRae
6e37305765 [host] d12: check if the device was removed during init 2024-03-11 20:27:36 +11:00
Geoffrey McRae
dd6c79594b [host] d12: check for failure to obtain d3d12 functions 2024-03-11 20:16:00 +11:00
Geoffrey McRae
ce9ed5da5d [host] d12: add additional debug tracing 2024-03-11 20:12:41 +11:00
Geoffrey McRae
fdad5daff8 [host/common] d12: add debug tracing 2024-03-11 19:14:54 +11:00
Geoffrey McRae
8d25469d27 [host] d12: limit the dx11 interop level to one version 2024-03-11 18:44:26 +11:00
Geoffrey McRae
8c5d1d47ee [host] nvfbc: mark NvFBC as deprecated 2024-03-11 14:16:12 +11:00
Geoffrey McRae
90398bc04f [host] app: do not try to use deprecated interfaces automatically 2024-03-11 14:16:12 +11:00
Geoffrey McRae
989fe2bb0b [host] d12: test if creating resources in the heap works at init
AMD GPUs and older NVidia GPUs can initialize fine but fail when we
start to create resources in the shared memory heap, we must test it
early to detect this so we can fallback to a working capture method.
2024-03-11 14:16:12 +11:00
Geoffrey McRae
7a41169104 [doc] consistency fix in example output 2024-03-11 00:59:46 +11:00
Geoffrey McRae
0b4322d921 [doc] remove NvFBC tuning recommendation now D12 is faster 2024-03-09 23:06:37 +11:00
Geoffrey McRae
b251b22a64 [doc] fix ivshmem_kvmfr tree structure 2024-03-09 13:36:22 +11:00
Geoffrey McRae
90b27ae1f7 [host] d12: revert ivshmem heap order change
Moving this prevented the RX580 crash early in init, but later
presents during the capture. As we want to ensure fallback to DXGI
if this happens we need to catch this fault during init. This moves
the order back so that we fail back into a working state.
2024-03-09 12:11:54 +11:00
Geoffrey McRae
4d388d6b9b [host] d12: move ivshmem heap creation to later in init
This has been moved to try to isolate a failure with RX580 startup
2024-03-09 11:56:14 +11:00
Geoffrey McRae
a88783e5b7 [doc] fix lack of consistency of Recommended 2024-03-09 11:35:52 +11:00
Geoffrey McRae
da820769e8 [host] windows: fix crash on failure to init a capture interface 2024-03-09 11:30:35 +11:00
Geoffrey McRae
d5b32225f4 [host] d12: don't attempt to use realtime priority
Some GPUs such as the RX580 seem to completely crash when attempting
to use `D3D12_COMMAND_QUEUE_PRIORITY_GLOBAL_REALTIME`.
2024-03-09 11:00:44 +11:00
Geoffrey McRae
778c21070c [doc] ammend ivshmem_kvmfr to make cgroups and permissions clearer 2024-03-08 23:31:32 +11:00
Geoffrey McRae
cae410d4de [doc] the nvidia open drivers now support DMABUF 2024-03-08 22:57:22 +11:00
Geoffrey McRae
064a605208 [doc] fix broken reference 2024-03-08 22:55:09 +11:00
Geoffrey McRae
279357e205 [doc] remove the module page as it's now part of installation 2024-03-08 22:53:43 +11:00
Geoffrey McRae
98aade2ec9 [doc] update host usage documentation 2024-03-08 22:41:32 +11:00
Geoffrey McRae
4acea9fa25 [doc] fix document reference 2024-03-08 18:37:40 +11:00
Geoffrey McRae
01efbc62c4 [doc] fix typos (again) 2024-03-08 18:34:22 +11:00
Geoffrey McRae
ed512f5943 [doc] fix typos 2024-03-08 18:32:38 +11:00
Geoffrey McRae
4a4f72ba38 [doc] update and restructure installation documentation 2024-03-08 18:22:07 +11:00
Geoffrey McRae
eb31815b46 [host] windows: add OutputDebugString capture for diagnostics 2024-03-07 11:34:46 +11:00
Geoffrey McRae
545e736389 [host] windows: handle graceful shutdown on user switch 2024-03-06 15:02:37 +11:00
Geoffrey McRae
6a72633674 [host] windows: move the service log to the temp directory
Often this log is provided instead of the actual host log, as this
log is largely useless for debugging this moves it to the temp
directory out of view of the user.
2024-03-06 13:11:48 +11:00
Geoffrey McRae
9123984ecc [host] windows: rotate the host log out keeping at most 3 prior versions 2024-03-06 12:59:15 +11:00
Geoffrey McRae
d81395b672 [common] option: send all output to stderr 2024-03-04 21:21:46 +11:00
Geoffrey McRae
bfadf0a427 [host] app: print list of valid capture interfaces 2024-03-04 21:09:39 +11:00
Geoffrey McRae
03662f45a7 [host] nvfbc: add warning to encourage migration to D12 2024-03-04 16:34:47 +11:00
Geoffrey McRae
a4e761bedc [host] win: make D12 the default copy backend 2024-03-04 16:31:14 +11:00
Geoffrey McRae
beb8de922d [host] dxgi: remove the deprecated and broken d3d12 copyBackend
This backend has been deprecated and has been replaced by the new D12 capture
interface.
2024-03-04 16:29:43 +11:00
Geoffrey McRae
e247f1fc7b [host] d12: enlarge downsampler damage rects 2024-02-28 20:34:09 +11:00
Geoffrey McRae
4463ca15f6 [host] d12: added downsampler 2024-02-28 20:21:47 +11:00
Geoffrey McRae
97d91a32c8 [host] d12: make effects fully self-contained 2024-02-28 16:05:56 +11:00
Geoffrey McRae
2d41cda640 [host] d12: fix target for wait fence when effects are active 2024-02-28 12:31:56 +11:00
Geoffrey McRae
a894348530 [host] d12: correct the pitch when HDR16 is in use 2024-02-28 12:23:41 +11:00
Geoffrey McRae
ad7ac6540f [host] d12: implement hdr16 to hdr10 conversion 2024-02-28 11:59:58 +11:00
Geoffrey McRae
0184ddeedd [host] d12: properly handle format changes by effects 2024-02-28 09:40:35 +11:00
Geoffrey McRae
b87d8d2f33 [host] d12: disable RGB24 if the capture is HDR 2024-02-28 07:46:47 +11:00
Geoffrey McRae
5c4540ed8b [host] d12: pass frame information in a description structure 2024-02-28 07:30:39 +11:00
Geoffrey McRae
c7f1aadb9e [host] d12: pass back rotation metadata to the client 2024-02-28 05:54:40 +11:00
Geoffrey McRae
57ac020c8c [host] linux: update to build again 2024-02-27 19:14:58 +11:00
Geoffrey McRae
71b826458d [host] fix host-windows-cross github compilation 2024-02-27 19:14:58 +11:00
Geoffrey McRae
4408359597 [host] d12: fix damage tracking with RGB24 enabled 2024-02-24 09:04:59 +11:00
Geoffrey McRae
2f3ca443cf [host] d12: Use the gpu reported pitch instead of assuming w * 4 2024-02-24 07:57:50 +11:00
Geoffrey McRae
66049cf763 [host] d12: fix, send the current dirtyRects, not the old 2024-02-23 17:38:45 +11:00
Geoffrey McRae
a6dc8a9db3 [host] d12: fix damage tracking on re-init 2024-02-23 17:28:09 +11:00
Geoffrey McRae
dc4d93f50a [host] d12: remove extra copies in damage tracking 2024-02-23 17:24:25 +11:00
Geoffrey McRae
3b43dcb80d [host] d12: fix type of function argument 2024-02-23 11:00:18 +11:00
Geoffrey McRae
9de047d9cb [host] d12: implement damage aware copy 2024-02-23 10:54:08 +11:00
Geoffrey McRae
1098b7e6bd [host] d12: cosmetics 2024-02-23 08:38:32 +11:00
Geoffrey McRae
055d5527ef [host] d12: allow specifying adapter and output to capture 2024-02-23 08:14:24 +11:00
Geoffrey McRae
b1313980fb [host] d12: make RGB24 optional, disabled by default 2024-02-05 05:17:55 +11:00
Geoffrey McRae
319241b597 [host] d12: use a GPU side fence instead of CPU side 2024-02-05 04:27:04 +11:00
Geoffrey McRae
b0b851dd4b [host] d12: fix incorrect format presented to extra clients 2024-02-05 04:20:38 +11:00
Geoffrey McRae
60b01566e1 [host] d12: implement initial RGB24 support 2024-02-05 02:49:08 +11:00
Geoffrey McRae
4076377820 [host] win: add comRef helpers for leak identification and tracking 2024-02-05 02:49:08 +11:00
Geoffrey McRae
0b210a280d [all] update the copyright to 2024 2024-02-01 17:16:31 +11:00
Geoffrey McRae
a4fede01f3 [host] d12: general cleanups 2024-02-01 17:13:18 +11:00
Geoffrey McRae
071e4323fa [host] windows: make DXGI the default capture interface, D12 is not ready 2024-02-01 14:48:44 +11:00
Geoffrey McRae
be82b7e578 [host] d12: add wrappers for backend functions 2024-01-31 10:18:56 +11:00
Geoffrey McRae
c07b72883a [host] d12: adjust backend API to allow multiple instances 2024-01-31 09:43:01 +11:00
Geoffrey McRae
462d8187b6 [host] d12: handle error when windows switches to the secure desktop 2024-01-31 05:42:30 +11:00
Geoffrey McRae
4523b9ba00 [host] d12: fix failure to send mouse shape updates 2024-01-31 05:28:03 +11:00
Geoffrey McRae
cae4b2f4f9 [host] windows: fix compilation under gcc 2024-01-31 01:33:43 +11:00
Geoffrey McRae
72b25b99bc [host] add new D12 capture interface
Note, this capture interface is not yet feature complete but does seem
to be stable.
2024-01-31 00:29:55 +11:00
Geoffrey McRae
e376e6fb53 [host] app: revert unintended change from last commit 2024-01-27 23:19:42 +11:00
Geoffrey McRae
34e8a2255e [host] dxgi: d3d12 now writes direclty into ivshmem
This is still incomplete as d3d12 doesn't have any proper sync with the
captured frame and as such is still not suggested for general usage. This
change though is monumental for this project as it removes a full memory
copy reducing bandwidth consumption enormously.
2024-01-27 22:57:13 +11:00
Geoffrey McRae
adaf40e2bf [host] dxgi: Fix d3d12 32-bit output
Fixes #1100
2024-01-27 20:07:52 +11:00
Geoffrey McRae
84dd68dd2b [host] dxgi: correct 24-bit packed output height calculation bug 2024-01-27 11:14:04 +11:00
Geoffrey McRae
738a04d0bc [host] dxgi: fix packed texture height calculation 2024-01-27 10:56:23 +11:00
Geoffrey McRae
2316a5e64d [host] dxgi: ensure 24-bit packed output is properly aligned 2024-01-27 10:11:01 +11:00
Geoffrey McRae
47ad93f48d [host] common: fix compilation on clang 2024-01-27 10:10:48 +11:00
Geoffrey McRae
c5cbb8aa46 [host] dxgi: enable 24-bit mode by default
General community feedback with this enabled has been positive and we
can now transition to enabling by default.
2024-01-27 02:28:09 +11:00
Geoffrey McRae
ad00aaacd0 [obs] fix non-dmabuf 24-bit imports
OBS `GS_RGBA` maps to the sRGB color space which breaks our mapping
kludge, as such we need to use the UNORM variants to avoid this
2024-01-27 02:14:05 +11:00
Geoffrey McRae
1b75ae0762 [obs] fix 24-bit import support with dmabuf 2024-01-27 00:44:38 +11:00
Geoffrey McRae
5b3cc4cd48 [cmake] MakeObject: ensure embedded objects are null terminated 2024-01-27 00:44:38 +11:00
Geoffrey McRae
7247fadad8 [client] egl: fix post processing failure when converting pixel formats 2024-01-25 17:51:06 +11:00
Geoffrey McRae
c2237f29ae [client] x11: fix typo
Closes #1105
2024-01-02 08:51:13 +11:00
Tudor Brindus
e5a9c0242f [client] wayland: libdecor maximize request should maximize, not minimize 2023-12-24 15:30:19 +11:00
Quantum
537218d6ae [client] wayland: honour fullscreen and maximize in libdecor
We never added the functionality when the parameters were passed to
libdecor_shellInit.
2023-12-22 14:08:48 +11:00
Geoffrey McRae
f05151c9a6 [host] nvfbc: fix compilation with new debug code 2023-12-07 16:33:54 +11:00
Geoffrey McRae
b776b00a67 [common] host: fix compliation on windows 2023-12-07 16:11:28 +11:00
Geoffrey McRae
4b4e07875d [common] debug: fix compilation on windows 2023-12-07 15:46:31 +11:00
Geoffrey McRae
6104956a27 [common] reformat the debug output to be more useful 2023-12-07 15:37:54 +11:00
Geoffrey McRae
3668040892 [client] pipewire: correct pipewire_latency as per the docs
see: https://docs.pipewire.org/structpw__time.html
2023-12-06 22:26:20 +11:00
Geoffrey McRae
8cd002f1b2 [client] x11: fix incorrect pointer reference, fixes clipboard
Thanks to @JJRcop for bisecting to discover the fault
2023-12-01 09:12:38 +11:00
Geoffrey McRae
22d949c411 [client] egl: fix rgb24 regression
We need the alpha channel for this data type
2023-11-21 12:20:46 +11:00
Geoffrey McRae
43a3fb0db3 [client] egl: RGB24 improvements
This patch performs several changes.

* Alters the fourcc codes to types that ignore the alpha channel where
  possible to allow the gpu to internally use 24-bit formats.
* Attempts to use DRM_FORMAT_RGB888 first as some GPUs may support this
* If DMABUF is not in use the data is now imported directly as RGB24
  without the post-processing shader
2023-11-21 12:01:45 +11:00
Geoffrey McRae
8d27d9e2e2 [common] rect: fix avx alignment issue take 2 2023-11-19 18:01:34 +11:00
Geoffrey McRae
660b4b8ec8 [common] rects: fix avx implementation for unaligned accesses 2023-11-19 17:16:22 +11:00
Geoffrey McRae
4911e129f8 [common] time: improve flow with compiler hints 2023-11-19 16:31:45 +11:00
Geoffrey McRae
d3ee5bddde [common] rect/framebuffer: improve avx implementations 2023-11-19 15:45:15 +11:00
Geoffrey McRae
0ce4c34c37 [client] egl: fix non-dma RGB24 import path 2023-11-19 09:42:37 +11:00
Geoffrey McRae
584de4133f [common] fix compilation on clang 2023-11-19 03:20:34 +11:00
Geoffrey McRae
3330f83af6 [common] add runtime detection and selection of AVX/AVX2 support 2023-11-19 02:52:11 +11:00
Geoffrey McRae
5d4c1d348c [all] refactor cpuInfo function names 2023-11-19 01:22:09 +11:00
Geoffrey McRae
750cab83a3 Revert "[common] add AVX/AVX2 memory copy implementations"
This reverts commit e61678ef1b.
GCC only supports multi-versioning in C++
2023-11-19 00:18:48 +11:00
Geoffrey McRae
e61678ef1b [common] add AVX/AVX2 memory copy implementations 2023-11-19 00:09:42 +11:00
Geoffrey McRae
6357df1a7a [client] egl: fix non-dma texture stride issue 2023-11-15 17:40:57 +11:00
Geoffrey McRae
1f4395570c [obs] fix timeout when unsupported frame type is provided 2023-11-15 17:39:09 +11:00
Geoffrey McRae
accf300c6c [host] dxgi: fix failure to reset texture state on fast restarts 2023-11-15 17:31:37 +11:00
Geoffrey McRae
a0fd03d328 [repo] update LGMP submodule 2023-11-13 14:03:19 +11:00
Geoffrey McRae
929e88b9d3 [all] provide conditional path optimization hints to the compiler 2023-11-12 18:26:08 +11:00
Geoffrey McRae
7bea919352 [common] time: prevent possible div by zero on windows 2023-11-12 06:56:37 +11:00
Geoffrey McRae
96b5892c31 [host] app: prevent possible null deref and resource leak 2023-11-12 06:44:20 +11:00
Geoffrey McRae
b14aad7118 [host] dxgi: remove uneeded variable + minor cosmetic changes 2023-11-12 06:36:04 +11:00
Geoffrey McRae
7321ca6768 [host] windows: fix stdout/stderr resource leak 2023-11-12 06:20:29 +11:00
Geoffrey McRae
cd6485f2ed [host] downsample: fix resource leak on failure 2023-11-12 05:59:47 +11:00
Geoffrey McRae
7bcad37568 [host] platform: Close the exitEvent when done 2023-11-12 05:59:14 +11:00
Geoffrey McRae
ba8075a9fd [host] app: fix unchecked return value 2023-11-11 20:50:42 +11:00
Geoffrey McRae
3bad3837b4 [host] fix copy-paste error 2023-11-11 20:47:36 +11:00
Geoffrey McRae
084ebe5035 [host] dxgi: fix potential buffer out of bounds access 2023-11-11 20:41:10 +11:00
Geoffrey McRae
d480b674ca [host] dxgi: fix invalid array access via wrong variable 2023-11-11 20:37:58 +11:00
Geoffrey McRae
10e30eec57 [host] dxgi: fix possible null dereference 2023-11-11 20:36:53 +11:00
Geoffrey McRae
38b6b0ac40 [common] windows/event: fix control flow issue 2023-11-11 20:34:30 +11:00
Geoffrey McRae
503efdd0d8 [host] dxgi: fix failure to call FreeLibrary for d3d12 2023-11-11 20:31:53 +11:00
Geoffrey McRae
75e10688d4 [repo] update PureSpice submodule 2023-11-11 15:51:37 +11:00
Geoffrey McRae
ec88a52fe2 [common] ivshmem: fix possible resource leak 2023-11-11 14:04:54 +11:00
Geoffrey McRae
a28deae569 [client] util: fix invalid pointer arithmatic 2023-11-11 14:03:40 +11:00
Geoffrey McRae
cf51503a54 [client] X11/i3: write directly into sun_path to avoid strncpy 2023-11-11 13:48:41 +11:00
Geoffrey McRae
aa42751743 [client] common: fix time of check/time of use issue 2023-11-11 13:48:41 +11:00
Geoffrey McRae
9a53880b9b [common] ivshmem: fix failure to check ioctl for error result 2023-11-11 13:48:41 +11:00
Geoffrey McRae
a3b51220ed [common] option: remove const qualifier from shortopt 2023-11-11 13:48:41 +11:00
Geoffrey McRae
17fce1cf78 [client] util: fix failure to check result of ftell for error 2023-11-11 13:48:41 +11:00
Geoffrey McRae
9f3f8cc5bd [client] splash: remove 0 array specifier from func prototype 2023-11-11 13:48:41 +11:00
Geoffrey McRae
0524980cb4 [client] msg: make it clear we ignore the return for ll_shift 2023-11-11 13:48:41 +11:00
Geoffrey McRae
a0f5907cb6 [client] overlay: prevent possible divide by zero 2023-11-11 13:48:41 +11:00
Geoffrey McRae
0a9784d09d [client] main: fix possible dereference of null g_state.ds 2023-11-11 13:48:41 +11:00
Geoffrey McRae
120e063a10 [client] main: prevent possible null pointer dereference 2023-11-11 13:48:41 +11:00
Geoffrey McRae
f59ef4422a [client] app: prevent possible out of bounds array access 2023-11-11 13:48:41 +11:00
Geoffrey McRae
417c9cf092 [client] opengl: act on glBufferSubData failure 2023-11-11 13:48:41 +11:00
Geoffrey McRae
852825a97e [client] util: fix failure to dereference pointer 2023-11-11 13:48:41 +11:00
Geoffrey McRae
cce12508cc [egl] shader: fix reliance on null terminated strings
Compiled in resources often will not contain a null terminator, as such
we must not use functions that rely on it. This implements a memsearch
function that performs like strstr on a buffer instead of a null
terminated string.
2023-11-11 13:48:41 +11:00
Geoffrey McRae
43f9a4c0e1 [client] egl: fix potential integer underflow 2023-11-11 13:48:41 +11:00
Geoffrey McRae
ee5c02f72a [client] egl: fix potential resource leak 2023-11-11 13:48:41 +11:00
Geoffrey McRae
55fa5cc851 [client] egl: fix integer division into float 2023-11-11 13:48:41 +11:00
Geoffrey McRae
b70811dcb9 [client] x11: pass large struct by reference 2023-11-11 13:48:41 +11:00
Geoffrey McRae
3c1405719c [client] wayland: fix use after free bugs 2023-11-11 13:48:41 +11:00
Geoffrey McRae
f6befb4567 [client] wayland: formatting 2023-11-11 13:48:41 +11:00
Jonathan Rubenstein
62aef5a240 [doc] build: Move NvFBC note into don't build warning
Also:
   - Add link to warning (#dont-build-the-host)
2023-11-11 10:32:15 +11:00
Jonathan Rubenstein
4f508d320a [doc] words: Sort using sort_words.py 2023-11-11 10:31:51 +11:00
Jonathan Rubenstein
29f1434270 [doc] sort_words: Create sort_words.py to make words.txt easier to maintain
sort_words.py outputs a diff that if applied will sort words.txt

It has a few options:
    - '--add-word': Add a word before sorting (usable multiple times)
    - '--save': Save changes to file instead of only outputting a diff
    - '--quiet': Don't output a diff
2023-11-11 10:31:51 +11:00
Geoffrey McRae
27f3af8221 [host] nvfbc: cosmetics 2023-11-11 09:08:56 +11:00
Geoffrey McRae
cb849b287c [hosts] nvfbc: exit loop early if ystart is > then dataHeight 2023-11-11 09:08:08 +11:00
Geoffrey McRae
8630fd20ad [common] rects: simplify unaligned copy function 2023-11-11 09:07:00 +11:00
Geoffrey McRae
0057cf5377 [host] nvfbc: add additional debug output 2023-11-10 08:01:03 +11:00
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  '&nbsp;' 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
318 changed files with 30793 additions and 12402 deletions

View File

@@ -2,7 +2,7 @@ name: build
on: [push, pull_request]
jobs:
client:
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
@@ -15,12 +15,6 @@ jobs:
- uses: actions/checkout@v2
with:
submodules: recursive
- name: Install libdecor PPA
run: sudo add-apt-repository ppa:christianrauch/libdecoration
if: ${{ matrix.wayland_shell == 'libdecor' }}
- name: Install PipeWire repository
run: |
echo 'deb [trusted=yes] https://pipewire-ubuntu.quantum5.workers.dev ./' | sudo tee /etc/apt/sources.list.d/pipewire.list
- name: Update apt
run: |
sudo apt-get update
@@ -32,6 +26,7 @@ jobs:
libgl-dev libgles-dev \
libx11-dev libxss-dev libxi-dev libxinerama-dev libxcursor-dev libxpresent-dev \
libwayland-dev libxkbcommon-dev \
libfontconfig-dev \
libsamplerate0-dev libpipewire-0.3-dev libpulse-dev \
$([ '${{ matrix.wayland_shell }}' = libdecor ] && echo 'libdecor-0-dev libdbus-1-dev') \
$([ '${{ matrix.compiler.cc }}' = clang ] && echo 'clang-tools')
@@ -76,16 +71,13 @@ jobs:
- uses: actions/checkout@v2
with:
submodules: recursive
- name: Install PipeWire repository
run: |
echo 'deb [trusted=yes] https://pipewire-ubuntu.quantum5.workers.dev ./' | sudo tee /etc/apt/sources.list.d/pipewire.list
- name: Update apt
run: |
sudo apt-get update
- name: Install Linux host dependencies
run: |
sudo apt-get install binutils-dev libxcb-xfixes0-dev \
libpipewire-0.3-dev
sudo apt-get install binutils-dev libglib2.0-dev libxcb-xfixes0-dev \
libpipewire-0.3-dev libxcb-shm0-dev
- name: Configure Linux host
run: |
mkdir host/build

View File

@@ -3,16 +3,36 @@ on: pull_request
jobs:
authors:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- uses: actions/checkout@v1
- name: Check AUTHORS file
id: check-authors
run: |
user="$(curl -H 'Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' -s https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }} | jq -r .user.login)"
echo "user=$user" >> "$GITHUB_OUTPUT"
echo "Checking if GitHub user $user is in AUTHORS file..."
if grep -q -E '> \('"$user"'\)' AUTHORS; then
echo "$user found in AUTHORS file, all good!"
else
echo "$user not found in AUTHORS file."
echo "Please add yourself to the AUTHORS file and try again."
exit 1
echo "not-found=yes" >> "$GITHUB_OUTPUT"
fi
- name: 'Not found: Create review requesting changes'
if: ${{ steps.check-authors.outputs.not-found }}
uses: actions/github-script@v7
with:
script: |
github.rest.pulls.createReview({
owner: context.issue.owner,
repo: context.issue.repo,
pull_number: context.issue.number,
event: "REQUEST_CHANGES",
body: "@${{ steps.check-authors.outputs.user }} not found in AUTHORS file.\n" +
"Please add yourself to the AUTHORS file and try again."
});
- name: 'Not found: Fail job'
if: ${{ steps.check-authors.outputs.not-found }}
run: exit 1

View File

@@ -67,3 +67,8 @@ Daniel Cordero <looking-glass@0xdc.io> (0xdc)
esi <git@esibun.net> (esibun)
MakiseKurisu <saberconer@gmail.com> (MakiseKurisu)
Zenithal <i@zenithal.me> (ZenithalHourlyRate)
Kamplom <6284968128@protonmail.ch> (kamplom)
Jacob McNamee <jacob@jacobmcnamee.com> (jacobmcnamee)
Marco Antonio J. Costa <marco.antonio.costa@gmail.com> (majcosta)
rs189 <35667100+rs189@users.noreply.github.com> (rs189)
Jérôme Poulin <jeromepoulin@gmail.com> (ticpu)

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.0)
cmake_minimum_required(VERSION 3.10)
project(looking-glass-client C CXX)
get_filename_component(PROJECT_TOP "${PROJECT_SOURCE_DIR}/.." ABSOLUTE)
@@ -42,25 +42,12 @@ add_feature_info(ENABLE_ASAN ENABLE_ASAN "AddressSanitizer support.")
option(ENABLE_UBSAN "Build with UndefinedBehaviorSanitizer" OFF)
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.")
option(ENABLE_PULSEAUDIO "Build with PulseAudio audio output support" ON)
add_feature_info(ENABLE_PULSEAUDIO ENABLE_PULSEAUDIO "PulseAudio audio support.")
if (NOT ENABLE_X11 AND NOT ENABLE_WAYLAND)
message(FATAL_ERROR "Either ENABLE_X11 or ENABLE_WAYLAND must be on")
endif()
add_compile_options(
"-Wall"
"-Wextra"
@@ -150,6 +137,8 @@ set(SOURCES
# Force cimgui to build as a static library.
set(IMGUI_STATIC "yes" CACHE STRING "Build as a static library")
add_definitions("-DCIMGUI_USE_OPENGL2=1")
add_definitions("-DCIMGUI_USE_OPENGL3=1")
add_subdirectory("${PROJECT_TOP}/resources" "${CMAKE_BINARY_DIR}/resources")
add_subdirectory("${PROJECT_TOP}/common" "${CMAKE_BINARY_DIR}/common" )
@@ -160,6 +149,7 @@ add_subdirectory("${PROJECT_TOP}/repos/cimgui" "${CMAKE_BINARY_DIR}/cimgui" E
add_subdirectory(displayservers)
add_subdirectory(renderers)
configure_file("${PROJECT_TOP}/resources/looking-glass-client.desktop.in" "${CMAKE_BINARY_DIR}/resources/looking-glass-client.desktop" @ONLY)
add_executable(looking-glass-client ${SOURCES})
target_compile_definitions(looking-glass-client PRIVATE CIMGUI_DEFINE_ENUMS_AND_STRUCTS=1)
@@ -190,4 +180,10 @@ install(TARGETS looking-glass-client
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
COMPONENT binary)
install(FILES "${CMAKE_BINARY_DIR}/resources/looking-glass-client.desktop"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/applications")
install(FILES "${PROJECT_TOP}/resources/lg-logo.svg"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/scalable/apps"
RENAME "looking-glass.svg")
feature_summary(WHAT ENABLED_FEATURES DISABLED_FEATURES)

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.0)
cmake_minimum_required(VERSION 3.10)
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.10)
project(audiodev_PipeWire LANGUAGES C)
find_package(PkgConfig)

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* Copyright © 2017-2025 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -48,6 +48,7 @@ struct PipeWire
{
struct pw_stream * stream;
struct spa_io_rate_match * rateMatch;
struct pw_time time;
int channels;
int sampleRate;
@@ -91,6 +92,14 @@ static void pipewire_onPlaybackProcess(void * userdata)
{
struct pw_buffer * pbuf;
#if PW_CHECK_VERSION(0, 3, 50)
if (pw_stream_get_time_n(pw.playback.stream, &pw.playback.time,
sizeof(pw.playback.time)) < 0)
#else
if (pw_stream_get_time(pw.playback.stream, &pw.playback.time) < 0)
#endif
DEBUG_ERROR("pw_stream_get_time failed");
if (!(pbuf = pw_stream_dequeue_buffer(pw.playback.stream)))
{
DEBUG_WARN("out of buffers");
@@ -115,6 +124,7 @@ static void pipewire_onPlaybackProcess(void * userdata)
return;
}
pbuf->size = frames;
sbuf->datas[0].chunk->offset = 0;
sbuf->datas[0].chunk->stride = pw.playback.stride;
sbuf->datas[0].chunk->size = frames * pw.playback.stride;
@@ -248,6 +258,7 @@ static void pipewire_playbackSetup(int channels, int sampleRate,
struct pw_properties * props =
pw_properties_new(
PW_KEY_APP_NAME , "Looking Glass",
PW_KEY_NODE_NAME , "Looking Glass",
PW_KEY_MEDIA_TYPE , "Audio",
PW_KEY_MEDIA_CATEGORY, "Playback",
@@ -401,20 +412,32 @@ static void pipewire_playbackMute(bool mute)
pw_thread_loop_unlock(pw.thread);
}
static size_t pipewire_playbackLatency(void)
static uint64_t pipewire_playbackLatency(void)
{
struct pw_time time = { 0 };
pw_thread_loop_lock(pw.thread);
#if PW_CHECK_VERSION(0, 3, 50)
if (pw_stream_get_time_n(pw.playback.stream, &time, sizeof(time)) < 0)
#else
if (pw_stream_get_time(pw.playback.stream, &time) < 0)
#endif
DEBUG_ERROR("pw_stream_get_time failed");
pw_thread_loop_unlock(pw.thread);
if (pw.playback.time.rate.num == 0)
return 0;
return time.delay + time.queued / pw.playback.stride;
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
// diff in ns
int64_t diff = SPA_TIMESPEC_TO_NSEC(&ts) - pw.playback.time.now;
// elapsed frames
int64_t elapsed =
(pw.playback.time.rate.denom * diff) /
(pw.playback.time.rate.num * SPA_NSEC_PER_SEC);
const int64_t buffered = pw.playback.time.buffered + pw.playback.time.queued;
int64_t latency = (buffered * 1000 / pw.playback.sampleRate) +
((pw.playback.time.delay - elapsed) * 1000 *
pw.playback.time.rate.num / pw.playback.time.rate.denom);
return max(0, -latency);
#else
return pw.playback.time.delay + pw.playback.time.queued / pw.playback.stride;
#endif
}
static void pipewire_recordStopStream(void)

View File

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

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* Copyright © 2017-2025 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.10)
project(displayservers LANGUAGES C)
set(DISPLAYSERVER_H "${CMAKE_BINARY_DIR}/include/dynamic/displayservers.h")
@@ -18,6 +18,16 @@ function(add_displayserver name)
add_subdirectory(${name})
endfunction()
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.")
if (NOT ENABLE_X11 AND NOT ENABLE_WAYLAND)
message(FATAL_ERROR "Either ENABLE_X11 or ENABLE_WAYLAND must be on")
endif()
# 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.10)
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-2023 The Looking Glass Authors
* Copyright © 2017-2025 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-2023 The Looking Glass Authors
* Copyright © 2017-2025 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -376,7 +376,7 @@ static void clipboardReadCancel(struct ClipboardRead * data)
static void clipboardReadCallback(uint32_t events, void * opaque)
{
struct ClipboardRead * data = opaque;
if (events & EPOLLERR)
if (events & EPOLLERR)
{
clipboardReadCancel(data);
return;
@@ -475,6 +475,7 @@ void waylandCBRequest(LG_ClipboardData type)
close(data->fd);
free(data->buf);
free(data);
return;
}
wlCb.currentRead = data;

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* Copyright © 2017-2025 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.10)
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.10)
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,275 @@
/**
* Looking Glass
* Copyright © 2017-2025 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, const char * appId, 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, appId);
libdecor_frame_set_title(state.libdecorFrame, title);
libdecor_frame_map(state.libdecorFrame);
if (fullscreen)
libdecor_frame_set_fullscreen(state.libdecorFrame, NULL);
if (maximize)
libdecor_frame_set_maximized(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.10)
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-2025 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, const char * appId, 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, appId);
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-2023 The Looking Glass Authors
* Copyright © 2017-2025 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -89,18 +89,25 @@ 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,
wl_fixed_from_int(-1), wl_fixed_from_int(-1),
wl_fixed_from_int(-1), wl_fixed_from_int(-1)
);
wp_viewport_set_destination(wlWm.viewport, width, height);
}
else
{
@@ -120,18 +127,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-2023 The Looking Glass Authors
* Copyright © 2017-2025 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-2023 The Looking Glass Authors
* Copyright © 2017-2025 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-2025 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, const char * appId, 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-2023 The Looking Glass Authors
* Copyright © 2017-2025 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-2023 The Looking Glass Authors
* Copyright © 2017-2025 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-2023 The Looking Glass Authors
* Copyright © 2017-2025 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -109,10 +109,17 @@ void waylandPresentationFrame(void)
return;
struct FrameData * data = malloc(sizeof(*data));
if (!data)
{
DEBUG_ERROR("out of memory");
return;
}
if (clock_gettime(wlWm.clkId, &data->sent))
{
DEBUG_ERROR("clock_gettime failed: %s\n", strerror(errno));
free(data);
return;
}
struct wp_presentation_feedback * feedback = wp_presentation_feedback(wlWm.presentation, wlWm.surface);

View File

@@ -0,0 +1,71 @@
cmake_minimum_required(VERSION 3.10)
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-2023 The Looking Glass Authors
* Copyright © 2017-2025 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-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 <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,184 +0,0 @@
/**
* 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 <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;
wlWm.floating = true;
enum xdg_toplevel_state * state;
wl_array_for_each(state, states)
{
switch (*state)
{
case XDG_TOPLEVEL_STATE_FULLSCREEN:
wlWm.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:
wlWm.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 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)
{
if (!wlWm.floating)
return;
wlWm.width = w;
wlWm.height = h;
xdg_surface_set_window_geometry(wlWm.xdgSurface, 0, 0, w, h);
wlWm.needsResize = true;
app_invalidateWindow(true);
waylandStopWaitFrame();
}

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* Copyright © 2017-2025 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-2023 The Looking Glass Authors
* Copyright © 2017-2025 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,22 +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[i];
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.width = params.w;
wlWm.height = params.h;
if (!waylandPollInit())
return false;
@@ -108,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.appId, params.fullscreen, params.maximize,
params.borderless, params.resizable))
return false;
if (!waylandEGLInit(params.w, params.h))
@@ -119,9 +171,6 @@ static bool waylandInit(const LG_DSInitParams params)
return false;
#endif
wlWm.width = params.w;
wlWm.height = params.h;
return true;
}
@@ -156,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-2023 The Looking Glass Authors
* Copyright © 2017-2025 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,13 +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;
bool floating;
uint32_t resizeSerial;
bool configured;
bool warpSupport;
double cursorX, cursorY;
@@ -134,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;
@@ -314,16 +300,8 @@ 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);
bool waylandWindowInit(const char * title, const char * appId, bool fullscreen, bool maximize, bool borderless, bool resizable);
void waylandWindowFree(void);
void waylandWindowUpdateScale(void);
void waylandSetWindowSize(int x, int y);
@@ -331,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-2023 The Looking Glass Authors
* Copyright © 2017-2025 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -85,7 +85,7 @@ static const struct wl_surface_listener wlSurfaceListener = {
.leave = wlSurfaceLeaveHandler,
};
bool waylandWindowInit(const char * title, bool fullscreen, bool maximize, bool borderless, bool resizable)
bool waylandWindowInit(const char * title, const char * appId, bool fullscreen, bool maximize, bool borderless, bool resizable)
{
wlWm.scale = wl_fixed_from_int(1);
@@ -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, appId, 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.10)
project(displayserver_X11 LANGUAGES C)
find_package(PkgConfig)

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* Copyright © 2017-2025 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-2023 The Looking Glass Authors
* Copyright © 2017-2025 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-2023 The Looking Glass Authors
* Copyright © 2017-2025 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -60,40 +60,40 @@ static void x11CBSelectionIncr(const XPropertyEvent e);
static void x11CBSelectionNotify(const XSelectionEvent e);
static void x11CBXFixesSelectionNotify(const XFixesSelectionNotifyEvent e);
bool x11CBEventThread(const XEvent xe)
bool x11CBEventThread(const XEvent * xe)
{
switch(xe.type)
switch(xe->type)
{
case SelectionRequest:
x11CBSelectionRequest(xe.xselectionrequest);
x11CBSelectionRequest(xe->xselectionrequest);
return true;
case SelectionClear:
x11CBSelectionClear(xe.xselectionclear);
x11CBSelectionClear(xe->xselectionclear);
return true;
case SelectionNotify:
x11CBSelectionNotify(xe.xselection);
x11CBSelectionNotify(xe->xselection);
return true;
case PropertyNotify:
if (xe.xproperty.state != PropertyNewValue)
if (xe->xproperty.state != PropertyNewValue)
break;
if (xe.xproperty.atom == x11atoms.SEL_DATA)
if (xe->xproperty.atom == x11atoms.SEL_DATA)
{
if (x11cb.lowerBound == 0)
return true;
x11CBSelectionIncr(xe.xproperty);
x11CBSelectionIncr(xe->xproperty);
return true;
}
break;
default:
if (xe.type == x11.eventBase + XFixesSelectionNotify)
if (xe->type == x11.eventBase + XFixesSelectionNotify)
{
XFixesSelectionNotifyEvent * sne = (XFixesSelectionNotifyEvent *)&xe;
XFixesSelectionNotifyEvent * sne = (XFixesSelectionNotifyEvent *)xe;
x11CBXFixesSelectionNotify(*sne);
return true;
}

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* Copyright © 2017-2025 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -26,7 +26,7 @@
#include "interface/displayserver.h"
bool x11CBEventThread(const XEvent xe);
bool x11CBEventThread(const XEvent * xe);
bool x11CBInit(void);
void x11CBNotice(LG_ClipboardData type);

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* Copyright © 2017-2025 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-2023 The Looking Glass Authors
* Copyright © 2017-2025 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-2023 The Looking Glass Authors
* Copyright © 2017-2025 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-2023 The Looking Glass Authors
* Copyright © 2017-2025 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-2023 The Looking Glass Authors
* Copyright © 2017-2025 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -71,9 +71,9 @@ static bool wm_i3_init(void)
return false;
struct sockaddr_un addr = { .sun_family = AF_UNIX };
char path[sizeof(addr.sun_path)];
char * path = (char *)&addr.sun_path;
int pathLen;
if ((pathLen = fread(path, 1, sizeof(path), fd)) <= 0)
if ((pathLen = fread(path, 1, sizeof(addr.sun_path), fd)) <= 0)
{
pclose(fd);
return false;
@@ -91,7 +91,6 @@ static bool wm_i3_init(void)
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");

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* Copyright © 2017-2025 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -229,7 +229,7 @@ static void x11CheckEWMHSupport(void)
x11.ewmhHasFocusEvent = true;
}
DEBUG_INFO("EWMH-complient window manager detected: %s", wmName);
DEBUG_INFO("EWMH-compliant window manager detected: %s", wmName);
x11.ewmhSupport = true;
if (strcmp(wmName, "i3") == 0)
@@ -343,7 +343,7 @@ static bool x11Init(const LG_DSInitParams params)
XClassHint hint =
{
.res_name = strdup(params.title),
.res_class = strdup("looking-glass-client")
.res_class = strdup(params.appId)
};
XSetClassHint(x11.display, x11.window, &hint);
free(hint.res_name);
@@ -699,7 +699,7 @@ static bool x11Init(const LG_DSInitParams params)
XMoveWindow(x11.display, x11.window, params.x, params.y);
if (params.fullscreen)
x11SetFullscreen(true);
x11.doFullscreenOnExpose = true;
XSetLocaleModifiers(""); // Load XMODIFIERS
x11.xim = XOpenIM(x11.display, 0, 0, 0);
@@ -897,7 +897,7 @@ static int x11EventThread(void * unused)
XNextEvent(x11.display, &xe);
// call the clipboard handling code
if (x11CBEventThread(xe))
if (x11CBEventThread(&xe))
continue;
switch(xe.type)
@@ -946,6 +946,11 @@ static int x11EventThread(void * unused)
{
atomic_store(&x11.lastWMEvent, microtime());
x11.invalidateAll = true;
if (x11.doFullscreenOnExpose)
{
x11SetFullscreen(true);
x11.doFullscreenOnExpose = false;
}
break;
}

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* Copyright © 2017-2025 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -71,6 +71,7 @@ struct X11DSState
_Atomic(uint64_t) lastWMEvent;
bool invalidateAll;
bool doFullscreenOnExpose;
int xpresentOp;
bool jitRender;

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* Copyright © 2017-2025 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-2023 The Looking Glass Authors
* Copyright © 2017-2025 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-2023 The Looking Glass Authors
* Copyright © 2017-2025 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-2023 The Looking Glass Authors
* Copyright © 2017-2025 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-2023 The Looking Glass Authors
* Copyright © 2017-2025 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-2023 The Looking Glass Authors
* Copyright © 2017-2025 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -84,6 +84,7 @@ LG_DSPointer;
typedef struct LG_DSInitParams
{
const char * title;
const char * appId;
int x, y, w, h;
bool center;
bool fullscreen;

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* Copyright © 2017-2025 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-2023 The Looking Glass Authors
* Copyright © 2017-2025 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-2023 The Looking Glass Authors
* Copyright © 2017-2025 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -76,6 +76,8 @@ typedef struct LG_RendererFormat
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-2023 The Looking Glass Authors
* Copyright © 2017-2025 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-2023 The Looking Glass Authors
* Copyright © 2017-2025 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.10)
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.10)
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-2023 The Looking Glass Authors
* Copyright © 2017-2025 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, false))
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-2023 The Looking Glass Authors
* Copyright © 2017-2025 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-2023 The Looking Glass Authors
* Copyright © 2017-2025 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -77,7 +77,7 @@ 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,
false))
false, NULL))
{
DEBUG_ERROR("Failed to compile the damage shader");
return false;

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* Copyright © 2017-2025 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-2023 The Looking Glass Authors
* Copyright © 2017-2025 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -114,13 +114,13 @@ static bool egl_initDesktopShader(
if (!egl_shaderCompile(shader->shader,
vertex_code , vertex_size,
fragment_code, fragment_size,
useDMA))
useDMA, NULL))
{
return false;
}
shader->uTransform = egl_shaderGetUniform(shader->shader, "transform" );
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" );
@@ -206,6 +206,9 @@ bool egl_desktopInit(EGL * egl, EGL_Desktop ** desktop_, EGLDisplay * display,
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 );
@@ -337,6 +340,14 @@ 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;
break;
default:
DEBUG_ERROR("Unsupported frame format");
return false;
@@ -350,9 +361,10 @@ bool egl_desktopSetup(EGL_Desktop * desktop, const LG_RendererFormat format)
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");
@@ -365,9 +377,9 @@ bool egl_desktopSetup(EGL_Desktop * desktop, const LG_RendererFormat format)
bool egl_desktopUpdate(EGL_Desktop * desktop, const FrameBuffer * frame, int dmaFd,
const FrameDamageRect * damageRects, int damageRectsCount)
{
if (desktop->useDMA && dmaFd >= 0)
if (likely(desktop->useDMA && dmaFd >= 0))
{
if (egl_textureUpdateFromDMA(desktop->texture, frame, dmaFd))
if (likely(egl_textureUpdateFromDMA(desktop->texture, frame, dmaFd)))
{
atomic_store(&desktop->processFrame, true);
return true;
@@ -403,8 +415,8 @@ bool egl_desktopUpdate(EGL_Desktop * desktop, const FrameBuffer * frame, int dma
return false;
}
if (egl_textureUpdateFromFrame(desktop->texture, frame,
damageRects, damageRectsCount))
if (likely(egl_textureUpdateFromFrame(desktop->texture, frame,
damageRects, damageRectsCount)))
{
atomic_store(&desktop->processFrame, true);
return true;
@@ -425,25 +437,28 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth,
{
EGL_Texture * tex;
int width, height;
bool dma;
if (desktop->useSpice)
if (unlikely(desktop->useSpice))
{
tex = desktop->spiceTexture;
width = desktop->spiceWidth;
height = desktop->spiceHeight;
dma = false;
}
else
{
tex = desktop->texture;
width = desktop->width;
height = desktop->height;
dma = desktop->useDMA;
}
if (outputWidth == 0 && outputHeight == 0)
if (unlikely(outputWidth == 0 || outputHeight == 0))
DEBUG_FATAL("outputWidth || outputHeight == 0");
enum EGL_TexStatus status;
if ((status = egl_textureProcess(tex)) != EGL_TEX_STATUS_OK)
if (unlikely((status = egl_textureProcess(tex)) != EGL_TEX_STATUS_OK))
{
if (status != EGL_TEX_STATUS_NOTREADY)
DEBUG_ERROR("Failed to process the desktop texture");
@@ -458,7 +473,7 @@ 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, desktop->useDMA);
width, height, outputWidth, outputHeight, dma);
unsigned int finalSizeX, finalSizeY;
EGL_Texture * texture = egl_postProcessGetOutput(desktop->pp,
@@ -498,7 +513,7 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth,
&desktop->dmaShader : &desktop->shader;
const float mapHDRGain =
desktop->maxCLL / desktop->peakLuminance;
(float)desktop->maxCLL / desktop->peakLuminance;
EGL_Uniform uniforms[] =
{
@@ -572,6 +587,7 @@ void egl_desktopSpiceConfigure(EGL_Desktop * desktop, int width, int height)
EGL_PF_BGRA,
width,
height,
width,
width * 4
))
{
@@ -593,9 +609,9 @@ void egl_desktopSpiceDrawFill(EGL_Desktop * desktop, int x, int y, int width,
for(int x = 0; x < width; ++x)
line[x] = color;
for(; y < height; ++y)
for(int dy = 0; dy < height; ++dy)
egl_textureUpdateRect(desktop->spiceTexture,
x, y, width, 1, sizeof(line), (uint8_t *)line, false);
x, y + dy, width, 1, width, sizeof(line), (uint8_t *)line, false);
atomic_store(&desktop->processFrame, true);
}
@@ -604,11 +620,12 @@ 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);
}
void egl_desktopSpiceShow(EGL_Desktop * desktop, bool show)
{
desktop->useSpice = show;
atomic_store(&desktop->processFrame, true);
}

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* Copyright © 2017-2025 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-2023 The Looking Glass Authors
* Copyright © 2017-2025 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -296,7 +296,7 @@ bool egl_screenToDesktop(struct FrameDamageRect * output, const double matrix[6]
void egl_desktopRectsRender(EGL_DesktopRects * rects)
{
if (!rects->count)
if (unlikely(!rects->count))
return;
glBindVertexArray(rects->vao);

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* Copyright © 2017-2025 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-2023 The Looking Glass Authors
* Copyright © 2017-2025 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 @@
#include "interface/renderer.h"
#include "common/util.h"
#include "common/debug.h"
#include "common/KVMFR.h"
#include "common/option.h"
@@ -580,7 +581,7 @@ static bool egl_onFrameFormat(LG_Renderer * renderer, const LG_RendererFormat fo
this->formatValid = true;
/* this event runs in a second thread so we need to init it here */
if (!this->frameContext)
if (unlikely(!this->frameContext))
{
static EGLint attrs[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
@@ -600,7 +601,7 @@ static bool egl_onFrameFormat(LG_Renderer * renderer, const LG_RendererFormat fo
}
}
if (this->scalePointer)
if (likely(this->scalePointer))
{
float scale = max(1.0f, (float)format.screenWidth / this->width);
egl_cursorSetScale(this->cursor, scale);
@@ -623,7 +624,8 @@ static bool egl_onFrame(LG_Renderer * renderer, const FrameBuffer * frame, int d
struct Inst * this = UPCAST(struct Inst, renderer);
uint64_t start = nanotime();
if (!egl_desktopUpdate(this->desktop, frame, dmaFd, damageRects, damageRectsCount))
if (unlikely(!egl_desktopUpdate(
this->desktop, frame, dmaFd, damageRects, damageRectsCount)))
{
DEBUG_INFO("Failed to to update the desktop");
return false;
@@ -632,12 +634,17 @@ static bool egl_onFrame(LG_Renderer * renderer, const FrameBuffer * frame, int d
INTERLOCKED_SECTION(this->desktopDamageLock, {
struct DesktopDamage * damage = this->desktopDamage + this->desktopDamageIdx;
if (damage->count == -1 || damageRectsCount == 0 ||
damage->count + damageRectsCount >= KVMFR_MAX_DAMAGE_RECTS)
if (unlikely(
damage->count == -1 ||
damageRectsCount == 0 ||
damage->count + damageRectsCount >= KVMFR_MAX_DAMAGE_RECTS))
{
damage->count = -1;
}
else
{
memcpy(damage->rects + damage->count, damageRects, damageRectsCount * sizeof(FrameDamageRect));
memcpy(damage->rects + damage->count, damageRects,
damageRectsCount * sizeof(FrameDamageRect));
damage->count += damageRectsCount;
}
});
@@ -1056,14 +1063,14 @@ static bool egl_render(LG_Renderer * renderer, LG_RendererRotate rotate,
accumulated->count = 0;
INTERLOCKED_SECTION(this->desktopDamageLock, {
if (!renderAll)
if (likely(!renderAll))
{
for (int i = 0; i < bufferAge; ++i)
{
struct DesktopDamage * damage = this->desktopDamage +
IDX_AGO(this->desktopDamageIdx, i, DESKTOP_DAMAGE_COUNT);
if (damage->count < 0)
if (unlikely(damage->count < 0))
{
renderAll = true;
break;
@@ -1087,7 +1094,7 @@ static bool egl_render(LG_Renderer * renderer, LG_RendererRotate rotate,
this->desktopDamage[this->desktopDamageIdx].count = 0;
});
if (!renderAll)
if (likely(!renderAll))
{
double matrix[6];
egl_screenToDesktopMatrix(matrix,
@@ -1101,7 +1108,7 @@ static bool egl_render(LG_Renderer * renderer, LG_RendererRotate rotate,
int count = this->overlayHistoryCount[idx];
struct Rect * damage = this->overlayHistory[idx];
if (count < 0)
if (unlikely(count < 0))
{
renderAll = true;
break;
@@ -1114,11 +1121,12 @@ static bool egl_render(LG_Renderer * renderer, LG_RendererRotate rotate,
);
}
accumulated->count = rectsMergeOverlapping(accumulated->rects, accumulated->count);
accumulated->count = rectsMergeOverlapping(accumulated->rects,
accumulated->count);
}
++this->overlayHistoryIdx;
if (this->destRect.w > 0 && this->destRect.h > 0)
if (likely(this->destRect.w > 0 && this->destRect.h > 0))
{
if (egl_desktopRender(this->desktop,
this->destRect.w, this->destRect.h,
@@ -1136,41 +1144,39 @@ static bool egl_render(LG_Renderer * renderer, LG_RendererRotate rotate,
renderLetterBox(this);
hasOverlay |= egl_damageRender(this->damage, rotate, newFrame ? desktopDamage : NULL);
hasOverlay |= invalidateWindow;
hasOverlay |=
egl_damageRender(this->damage, rotate, newFrame ? desktopDamage : NULL) |
invalidateWindow;
struct Rect damage[KVMFR_MAX_DAMAGE_RECTS + MAX_OVERLAY_RECTS + 2];
int damageIdx = app_renderOverlay(damage, MAX_OVERLAY_RECTS);
switch (damageIdx)
if (unlikely(damageIdx != 0))
{
case 0: // no overlay
break;
case -1: // full damage
if (damageIdx == -1)
hasOverlay = true;
// fallthrough
default:
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplOpenGL3_RenderDrawData(igGetDrawData());
for (int i = 0; i < damageIdx; ++i)
damage[i].y = this->height - damage[i].y - damage[i].h;
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplOpenGL3_RenderDrawData(igGetDrawData());
for (int i = 0; i < damageIdx; ++i)
damage[i].y = this->height - damage[i].y - damage[i].h;
}
if (damageIdx >= 0 && cursorState.visible)
if (likely(damageIdx >= 0 && cursorState.visible))
damage[damageIdx++] = cursorState.rect;
int overlayHistoryIdx = this->overlayHistoryIdx % DESKTOP_DAMAGE_COUNT;
if (hasOverlay)
if (unlikely(hasOverlay))
this->overlayHistoryCount[overlayHistoryIdx] = -1;
else
{
if (damageIdx > 0)
memcpy(this->overlayHistory[overlayHistoryIdx], damage, damageIdx * sizeof(struct Rect));
if (unlikely(damageIdx > 0))
memcpy(this->overlayHistory[overlayHistoryIdx],
damage, damageIdx * sizeof(struct Rect));
this->overlayHistoryCount[overlayHistoryIdx] = damageIdx;
}
if (!hasOverlay && !this->hadOverlay)
if (unlikely(!hasOverlay && !this->hadOverlay))
{
if (this->cursorLast.visible)
damage[damageIdx++] = this->cursorLast.rect;
@@ -1197,7 +1203,9 @@ static bool egl_render(LG_Renderer * renderer, LG_RendererRotate rotate,
this->cursorLast = cursorState;
preSwap(udata);
app_eglSwapBuffers(this->display, this->surface, damage, this->noSwapDamage ? 0 : damageIdx);
app_eglSwapBuffers(this->display, this->surface, damage,
this->noSwapDamage ? 0 : damageIdx);
return true;
}

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* Copyright © 2017-2025 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-2023 The Looking Glass Authors
* Copyright © 2017-2025 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-2023 The Looking Glass Authors
* Copyright © 2017-2025 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-2023 The Looking Glass Authors
* Copyright © 2017-2025 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -37,7 +37,10 @@ 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_PF_RGB_24_32
}
EGL_PixelFormat;
@@ -60,13 +63,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-2023 The Looking Glass Authors
* Copyright © 2017-2025 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-2023 The Looking Glass Authors
* Copyright © 2017-2025 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-2023 The Looking Glass Authors
* Copyright © 2017-2025 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-2023 The Looking Glass Authors
* Copyright © 2017-2025 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -72,16 +72,17 @@ typedef struct EGL_FilterOps
* 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, bool useDMA);
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 */
void (*setOutputResHint)(EGL_Filter * filter,
unsigned int x, unsigned int y);
/* returns the output resolution of the filter */
/* returns the output resolution and pixel format of the filter */
void (*getOutputRes)(EGL_Filter * filter,
unsigned int *x, unsigned int *y);
unsigned int *x, unsigned int *y, enum EGL_PixelFormat *pixFmt);
/* prepare the shader for use
* A filter can return false to bypass it */
@@ -104,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))
@@ -121,24 +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,
unsigned int desktopWidth, unsigned int desktopHeight,
bool useDMA)
{
return filter->ops.setup(filter, pixFmt, width, height, useDMA);
return filter->ops.setup(filter, pixFmt, width, height,
desktopWidth, desktopHeight, useDMA);
}
static inline void egl_filterSetOutputResHint(EGL_Filter * filter,
@@ -149,9 +162,9 @@ static inline void egl_filterSetOutputResHint(EGL_Filter * filter,
}
static inline void egl_filterGetOutputRes(EGL_Filter * filter,
unsigned int *x, unsigned int *y)
unsigned int *x, unsigned int *y, enum EGL_PixelFormat *pixFmt)
{
return filter->ops.getOutputRes(filter, x, y);
return filter->ops.getOutputRes(filter, x, y, pixFmt);
}
static inline bool egl_filterPrepare(EGL_Filter * filter)

View File

@@ -0,0 +1,221 @@
/**
* Looking Glass
* Copyright © 2017-2025 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_32)
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, EGL_PF_BGRA, 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, enum EGL_PixelFormat *pixFmt)
{
EGL_Filter24bit * this = UPCAST(EGL_Filter24bit, filter);
*width = this->desktopWidth;
*height = this->desktopHeight;
*pixFmt = EGL_PF_BGRA;
}
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-2023 The Looking Glass Authors
* Copyright © 2017-2025 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -299,6 +299,7 @@ static bool egl_filterDownscaleImguiConfig(EGL_Filter * filter)
static bool egl_filterDownscaleSetup(EGL_Filter * filter,
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);
@@ -315,7 +316,7 @@ static bool egl_filterDownscaleSetup(EGL_Filter * filter,
b_shader_basic_vert , b_shader_basic_vert_size,
b_shader_downscale_frag,
b_shader_downscale_frag_size,
useDMA)
useDMA, NULL)
)
{
DEBUG_ERROR("Failed to compile the shader");
@@ -326,7 +327,7 @@ static bool egl_filterDownscaleSetup(EGL_Filter * filter,
b_shader_basic_vert, b_shader_basic_vert_size,
b_shader_downscale_linear_frag,
b_shader_downscale_linear_frag_size,
useDMA)
useDMA, NULL)
)
{
DEBUG_ERROR("Failed to compile the shader");
@@ -337,7 +338,7 @@ static bool egl_filterDownscaleSetup(EGL_Filter * filter,
b_shader_basic_vert, b_shader_basic_vert_size,
b_shader_downscale_lanczos2_frag,
b_shader_downscale_lanczos2_frag_size,
useDMA)
useDMA, NULL)
)
{
DEBUG_ERROR("Failed to compile the shader");
@@ -369,11 +370,12 @@ static bool egl_filterDownscaleSetup(EGL_Filter * filter,
}
static void egl_filterDownscaleGetOutputRes(EGL_Filter * filter,
unsigned int *width, unsigned int *height)
unsigned int *width, unsigned int *height, enum EGL_PixelFormat *pixFmt)
{
EGL_FilterDownscale * this = UPCAST(EGL_FilterDownscale, filter);
*width = this->width;
*height = this->height;
*pixFmt = this->pixFmt;
}
static bool egl_filterDownscalePrepare(EGL_Filter * filter)

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* Copyright © 2017-2025 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -209,6 +209,7 @@ static bool egl_filterFFXCASImguiConfig(EGL_Filter * filter)
static bool egl_filterFFXCASSetup(EGL_Filter * filter,
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);
@@ -221,7 +222,7 @@ static bool egl_filterFFXCASSetup(EGL_Filter * filter,
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)
useDMA, NULL)
)
{
DEBUG_ERROR("Failed to compile the shader");
@@ -253,11 +254,12 @@ static bool egl_filterFFXCASSetup(EGL_Filter * filter,
}
static void egl_filterFFXCASGetOutputRes(EGL_Filter * filter,
unsigned int *width, unsigned int *height)
unsigned int *width, unsigned int *height, enum EGL_PixelFormat *pixFmt)
{
EGL_FilterFFXCAS * this = UPCAST(EGL_FilterFFXCAS, filter);
*width = this->width;
*height = this->height;
*pixFmt = this->pixFmt;
}
static bool egl_filterFFXCASPrepare(EGL_Filter * filter)

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* Copyright © 2017-2025 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -127,7 +127,7 @@ static bool egl_filterFFXFSR1Init(EGL_Filter ** filter)
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,
false)
false, NULL)
)
{
DEBUG_ERROR("Failed to compile the Rcas shader");
@@ -323,6 +323,7 @@ static void egl_filterFFXFSR1SetOutputResHint(EGL_Filter * filter,
static bool egl_filterFFXFSR1Setup(EGL_Filter * filter,
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);
@@ -335,7 +336,7 @@ static bool egl_filterFFXFSR1Setup(EGL_Filter * filter,
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)
useDMA, NULL)
)
{
DEBUG_ERROR("Failed to compile the Easu shader");
@@ -382,11 +383,12 @@ static bool egl_filterFFXFSR1Setup(EGL_Filter * filter,
}
static void egl_filterFFXFSR1GetOutputRes(EGL_Filter * filter,
unsigned int *width, unsigned int *height)
unsigned int *width, unsigned int *height, enum EGL_PixelFormat *pixFmt)
{
EGL_FilterFFXFSR1 * this = UPCAST(EGL_FilterFFXFSR1, filter);
*width = this->width;
*height = this->height;
*pixFmt = this->pixFmt;
}
static bool egl_filterFFXFSR1Prepare(EGL_Filter * filter)

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* Copyright © 2017-2025 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-2023 The Looking Glass Authors
* Copyright © 2017-2025 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -43,6 +43,7 @@ bool egl_framebufferInit(EGL_Framebuffer ** fb)
if (!egl_textureInit(&this->tex, NULL, EGL_TEXTYPE_BUFFER))
{
DEBUG_ERROR("Failed to initialize the texture");
free(this);
return false;
}
@@ -64,14 +65,14 @@ 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;
}
GLuint tex;
egl_textureGet(this->tex, &tex, NULL, NULL);
egl_textureGet(this->tex, &tex, NULL, NULL, NULL);
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* Copyright © 2017-2025 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-2023 The Looking Glass Authors
* Copyright © 2017-2025 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-2023 The Looking Glass Authors
* Copyright © 2017-2025 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-2023 The Looking Glass Authors
* Copyright © 2017-2025 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -48,7 +48,7 @@ static const EGL_FilterOps * EGL_Filters[] =
struct EGL_PostProcess
{
Vector filters;
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;
}
@@ -616,7 +642,9 @@ bool egl_postProcessRun(EGL_PostProcess * this, EGL_Texture * tex,
//TODO: clean this up
GLuint _unused;
if (egl_textureGet(tex, &_unused, &sizeX, &sizeY) != EGL_TEX_STATUS_OK)
EGL_PixelFormat pixFmt;
if (egl_textureGet(tex, &_unused,
&sizeX, &sizeY, &pixFmt) != EGL_TEX_STATUS_OK)
return false;
if (atomic_exchange(&this->modified, false))
@@ -638,25 +666,35 @@ bool egl_postProcessRun(EGL_PostProcess * this, EGL_Texture * tex,
EGL_Filter * filter;
EGL_Texture * texture = tex;
vector_forEach(filter, &this->filters)
const Vector * lists[] =
{
egl_filterSetOutputResHint(filter, targetX, targetY);
&this->internalFilters,
&this->filters,
NULL
};
if (!egl_filterSetup(filter, tex->format.pixFmt, sizeX, sizeY, useDMA) ||
!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, 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, &pixFmt);
lastFilter = filter;
if (lastFilter)
egl_filterRelease(lastFilter);
// the first filter to run will convert to a normal texture
useDMA = false;
}
lastFilter = filter;
// the first filter to run will convert to a normal texture
useDMA = false;
}
this->output = texture;
this->outputX = sizeX;

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* Copyright © 2017-2025 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-2023 The Looking Glass Authors
* Copyright © 2017-2025 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 @@
#include "shader.h"
#include "common/debug.h"
#include "common/stringutils.h"
#include "util.h"
#include <stdlib.h>
@@ -65,7 +66,8 @@ void egl_shaderFree(EGL_Shader ** shader)
}
bool egl_shaderLoad(EGL_Shader * this,
const char * vertex_file, const char * fragment_file, bool useDMA)
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;
@@ -89,7 +91,7 @@ bool egl_shaderLoad(EGL_Shader * this,
bool ret = egl_shaderCompile(this,
vertex_code, vertex_size, fragment_code, fragment_size,
useDMA);
useDMA, defines);
free(vertex_code);
free(fragment_code);
@@ -210,30 +212,39 @@ static bool shaderCompile(EGL_Shader * this, const char * vertex_code,
bool egl_shaderCompile(EGL_Shader * this, const char * vertex_code,
size_t vertex_size, const char * fragment_code, size_t fragment_size,
bool useDMA)
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 search[] = "sampler2D";
const char replace[] = "samplerExternalOES";
const char * src = fragment_code;
const char * offset = NULL;
int instances = 0;
while((src = strstr(src, search)))
while((offset = memsearch(
fragment_code, fragment_size,
search , sizeof(search)-1,
offset)))
{
++instances;
src += strlen(search);
offset += sizeof(search)-1;
}
const int diff = (strlen(replace) - strlen(search)) * instances;
char * newCode = malloc(fragment_size + diff + 1);
const int diff = (sizeof(replace) - sizeof(search)) * instances;
const int newLen = fragment_size + diff;
newCode = malloc(newLen + 1);
if (!newCode)
{
DEBUG_ERROR("Out of memory");
return false;
goto exit;
}
src = fragment_code;
const char * src = fragment_code;
char * dst = newCode;
for(int i = 0; i < instances; ++i)
{
@@ -242,28 +253,104 @@ bool egl_shaderCompile(EGL_Shader * this, const char * vertex_code,
memcpy(dst, src, offset);
dst += offset;
src = pos + strlen(search);
src = pos + sizeof(search)-1;
memcpy(dst, replace, strlen(replace));
dst += strlen(replace);
memcpy(dst, replace, sizeof(replace)-1);
dst += sizeof(replace)-1;
}
const int final = fragment_size - (src - fragment_code);
memcpy(dst, src, final);
dst[final] = 0;
dst[final] = '\0';
bool result = shaderCompile(
this,
vertex_code, vertex_size,
newCode , fragment_size + diff);
free(newCode);
return result;
fragment_code = newCode;
fragment_size = newLen;
}
return shaderCompile(this,
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;
if (insertPos > 0)
--insertPos;
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)

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* Copyright © 2017-2025 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -93,15 +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, bool useDMA);
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,
bool useDMA);
bool useDMA, const EGL_ShaderDefine * defines);
void egl_shaderSetUniforms(EGL_Shader * shader, EGL_Uniform * uniforms,
int count);

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,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* Copyright © 2017-2025 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -94,14 +94,15 @@ void egl_textureFree(EGL_Texture ** tex)
}
bool egl_textureSetup(EGL_Texture * this, enum EGL_PixelFormat pixFmt,
size_t width, size_t height, size_t stride)
size_t width, size_t height, size_t stride, size_t pitch)
{
const struct EGL_TexSetup setup =
{
.pixFmt = pixFmt,
.width = width,
.height = height,
.stride = stride
.pixFmt = pixFmt,
.width = width,
.height = height,
.stride = stride,
.pitch = pitch,
};
if (!egl_texUtilGetFormat(&setup, &this->format))
@@ -129,7 +130,7 @@ bool egl_textureUpdate(EGL_Texture * this, const uint8_t * buffer, bool topDown)
}
bool egl_textureUpdateRect(EGL_Texture * this,
int x, int y, int width, int height, int stride,
int x, int y, int width, int height, int stride, int pitch,
const uint8_t * buffer, bool topDown)
{
x = clamp(x , 0, this->format.width );
@@ -147,8 +148,8 @@ bool egl_textureUpdateRect(EGL_Texture * this,
.y = y,
.width = width,
.height = height,
.pitch = stride / this->format.bpp,
.stride = stride,
.pitch = pitch,
.topDown = topDown,
.buffer = buffer
};
@@ -193,7 +194,7 @@ bool egl_textureUpdateFromDMA(EGL_Texture * this,
};
/* wait for completion */
framebuffer_wait(frame, this->format.bufferSize);
framebuffer_wait(frame, this->format.dataSize);
return this->ops.update(this, &update);
}

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* Copyright © 2017-2025 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -44,8 +44,8 @@ typedef struct EGL_TexUpdate
int x, y, width, height;
//pitch = row length in pixels
//stride = row length in bytes
//pitch = row length in pixels
//stride = row length in bytes
int pitch, stride;
union
@@ -92,7 +92,8 @@ typedef struct EGL_TextureOps
enum EGL_TexStatus (*process)(EGL_Texture * texture);
/* get the texture for use */
enum EGL_TexStatus (*get)(EGL_Texture * texture, GLuint * tex);
enum EGL_TexStatus (*get)(EGL_Texture * texture, GLuint * tex,
EGL_PixelFormat * fmt);
/* bind the texture for use */
enum EGL_TexStatus (*bind)(EGL_Texture * texture);
@@ -113,13 +114,13 @@ bool egl_textureInit(EGL_Texture ** texture, EGLDisplay * display,
void egl_textureFree(EGL_Texture ** tex);
bool egl_textureSetup(EGL_Texture * texture, enum EGL_PixelFormat pixFmt,
size_t width, size_t height, size_t stride);
size_t width, size_t height, size_t stride, size_t pitch);
bool egl_textureUpdate(EGL_Texture * texture, const uint8_t * buffer,
bool topDown);
bool egl_textureUpdateRect(EGL_Texture * texture,
int x, int y, int width, int height, int stride,
int x, int y, int width, int height, int stride, int pitch,
const uint8_t * buffer, bool topDown);
bool egl_textureUpdateFromFrame(EGL_Texture * texture,
@@ -132,13 +133,15 @@ bool egl_textureUpdateFromDMA(EGL_Texture * texture,
enum EGL_TexStatus egl_textureProcess(EGL_Texture * texture);
static inline EGL_TexStatus egl_textureGet(EGL_Texture * texture, GLuint * tex,
unsigned int * sizeX, unsigned int * sizeY)
unsigned int * sizeX, unsigned int * sizeY, EGL_PixelFormat * fmt)
{
if (sizeX)
*sizeX = texture->format.width;
if (sizeY)
*sizeY = texture->format.height;
return texture->ops.get(texture, tex);
if (fmt)
*fmt = texture->format.pixFmt;
return texture->ops.get(texture, tex, fmt);
}
enum EGL_TexStatus egl_textureBind(EGL_Texture * texture);

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* Copyright © 2017-2025 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -112,7 +112,7 @@ static bool egl_texBufferUpdate(EGL_Texture * texture, const EGL_TexUpdate * upd
DEBUG_ASSERT(update->type == EGL_TEXTYPE_BUFFER);
glBindTexture(GL_TEXTURE_2D, this->tex[0]);
glPixelStorei(GL_UNPACK_ROW_LENGTH, update->pitch);
glPixelStorei(GL_UNPACK_ROW_LENGTH, update->stride);
glTexSubImage2D(GL_TEXTURE_2D,
0,
update->x,
@@ -132,7 +132,8 @@ EGL_TexStatus egl_texBufferProcess(EGL_Texture * texture)
return EGL_TEX_STATUS_OK;
}
EGL_TexStatus egl_texBufferGet(EGL_Texture * texture, GLuint * tex)
EGL_TexStatus egl_texBufferGet(EGL_Texture * texture, GLuint * tex,
EGL_PixelFormat * fmt)
{
TextureBuffer * this = UPCAST(TextureBuffer, texture);
*tex = this->tex[0];
@@ -187,7 +188,7 @@ static bool egl_texBufferStreamUpdate(EGL_Texture * texture,
LG_LOCK(this->copyLock);
uint8_t * dst = this->buf[this->bufIndex].map +
texture->format.stride * update->y +
texture->format.pitch * update->y +
update->x * texture->format.bpp;
if (update->topDown)
@@ -195,19 +196,19 @@ static bool egl_texBufferStreamUpdate(EGL_Texture * texture,
const uint8_t * src = update->buffer;
for(int y = 0; y < update->height; ++y)
{
memcpy(dst, src, update->stride);
dst += texture->format.stride;
src += update->stride;
memcpy(dst, src, update->width * texture->format.bpp);
dst += texture->format.pitch;
src += update->pitch;
}
}
else
{
const uint8_t * src = update->buffer + update->stride * update->height;
const uint8_t * src = update->buffer + update->pitch * update->height;
for(int y = 0; y < update->height; ++y)
{
src -= update->stride;
memcpy(dst, src, update->stride);
dst += texture->format.stride;
src -= update->pitch;
memcpy(dst, src, update->width * texture->format.bpp);
dst += texture->format.pitch;
}
}
@@ -241,7 +242,8 @@ EGL_TexStatus egl_texBufferStreamProcess(EGL_Texture * texture)
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer->pbo);
glBindTexture(GL_TEXTURE_2D, tex);
glPixelStorei(GL_UNPACK_ROW_LENGTH, texture->format.pitch);
glPixelStorei(GL_UNPACK_ROW_LENGTH, texture->format.stride);
glTexSubImage2D(GL_TEXTURE_2D,
0, 0, 0,
texture->format.width,
@@ -259,7 +261,8 @@ EGL_TexStatus egl_texBufferStreamProcess(EGL_Texture * texture)
return EGL_TEX_STATUS_OK;
}
EGL_TexStatus egl_texBufferStreamGet(EGL_Texture * texture, GLuint * tex)
EGL_TexStatus egl_texBufferStreamGet(EGL_Texture * texture, GLuint * tex,
EGL_PixelFormat * fmt)
{
TextureBuffer * this = UPCAST(TextureBuffer, texture);
@@ -297,7 +300,7 @@ EGL_TexStatus egl_texBufferBind(EGL_Texture * texture)
GLuint tex;
EGL_TexStatus status;
if ((status = texture->ops.get(texture, &tex)) != EGL_TEX_STATUS_OK)
if ((status = texture->ops.get(texture, &tex, NULL)) != EGL_TEX_STATUS_OK)
return status;
glBindTexture(GL_TEXTURE_2D, tex);

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* Copyright © 2017-2025 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -47,7 +47,8 @@ bool egl_texBufferInit(EGL_Texture ** texture_, EGL_TexType type,
void egl_texBufferFree(EGL_Texture * texture_);
bool egl_texBufferSetup(EGL_Texture * texture_, const EGL_TexSetup * setup);
EGL_TexStatus egl_texBufferProcess(EGL_Texture * texture_);
EGL_TexStatus egl_texBufferGet(EGL_Texture * texture_, GLuint * tex);
EGL_TexStatus egl_texBufferGet(EGL_Texture * texture_, GLuint * tex,
EGL_PixelFormat * fmt);
EGL_TexStatus egl_texBufferBind(EGL_Texture * texture_);
bool egl_texBufferStreamInit(EGL_Texture ** texture_, EGL_TexType type,
@@ -55,4 +56,5 @@ bool egl_texBufferStreamInit(EGL_Texture ** texture_, EGL_TexType type,
bool egl_texBufferStreamSetup(EGL_Texture * texture_,
const EGL_TexSetup * setup);
EGL_TexStatus egl_texBufferStreamProcess(EGL_Texture * texture_);
EGL_TexStatus egl_texBufferStreamGet(EGL_Texture * texture_, GLuint * tex);
EGL_TexStatus egl_texBufferStreamGet(EGL_Texture * texture_, GLuint * tex,
EGL_PixelFormat * fmt);

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* Copyright © 2017-2025 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -37,13 +37,21 @@ typedef struct TexDMABUF
TextureBuffer base;
EGLDisplay display;
bool hasImportModifiers;
Vector images;
EGL_PixelFormat pixFmt;
unsigned fourcc;
unsigned width;
GLuint format;
}
TexDMABUF;
EGL_TextureOps EGL_TextureDMABUF;
static bool initDone = false;
static bool has24BitSupport = true;
static bool hasImportModifiers = true;
// internal functions
static void egl_texDMABUFCleanup(EGL_Texture * texture)
@@ -94,9 +102,13 @@ static bool egl_texDMABUFInit(EGL_Texture ** texture, EGL_TexType type,
this->display = display;
const char * client_exts = eglQueryString(this->display, EGL_EXTENSIONS);
this->hasImportModifiers =
util_hasGLExt(client_exts, "EGL_EXT_image_dma_buf_import_modifiers");
if (!initDone)
{
const char * client_exts = eglQueryString(this->display, EGL_EXTENSIONS);
hasImportModifiers =
util_hasGLExt(client_exts, "EGL_EXT_image_dma_buf_import_modifiers");
initDone = true;
}
return true;
}
@@ -113,9 +125,18 @@ static void egl_texDMABUFFree(EGL_Texture * texture)
free(this);
}
static bool egl_texDMABUFSetup(EGL_Texture * texture, const EGL_TexSetup * setup)
static bool texDMABUFSetup(EGL_Texture * texture)
{
TextureBuffer * parent = UPCAST(TextureBuffer, texture);
TexDMABUF * this = UPCAST(TexDMABUF , parent);
if (texture->format.pixFmt == EGL_PF_RGB_24 && !has24BitSupport)
{
this->pixFmt = EGL_PF_RGB_24_32;
this->width = texture->format.pitch / 4;
this->fourcc = DRM_FORMAT_ARGB8888;
this->format = GL_BGRA_EXT;
}
egl_texDMABUFCleanup(texture);
@@ -126,10 +147,10 @@ static bool egl_texDMABUFSetup(EGL_Texture * texture, const EGL_TexSetup * setup
glTexImage2D(GL_TEXTURE_EXTERNAL_OES,
0,
texture->format.intFormat,
texture->format.width,
this->width,
texture->format.height,
0,
texture->format.format,
this->format,
texture->format.dataType,
NULL);
}
@@ -139,6 +160,50 @@ static bool egl_texDMABUFSetup(EGL_Texture * texture, const EGL_TexSetup * setup
return true;
}
static bool egl_texDMABUFSetup(EGL_Texture * texture, const EGL_TexSetup * setup)
{
TextureBuffer * parent = UPCAST(TextureBuffer, texture);
TexDMABUF * this = UPCAST(TexDMABUF , parent);
this->pixFmt = texture->format.pixFmt;
this->width = texture->format.width;
this->fourcc = texture->format.fourcc;
this->format = texture->format.format;
return texDMABUFSetup(texture);
}
static EGLImage createImage(EGL_Texture * texture, int fd)
{
TextureBuffer * parent = UPCAST(TextureBuffer, texture);
TexDMABUF * this = UPCAST(TexDMABUF , parent);
const uint64_t modifier = DRM_FORMAT_MOD_LINEAR;
EGLAttrib attribs[] =
{
EGL_WIDTH , this->width ,
EGL_HEIGHT , texture->format.height,
EGL_LINUX_DRM_FOURCC_EXT , this->fourcc,
EGL_DMA_BUF_PLANE0_FD_EXT , fd,
EGL_DMA_BUF_PLANE0_OFFSET_EXT , 0,
EGL_DMA_BUF_PLANE0_PITCH_EXT , texture->format.pitch,
EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, (modifier & 0xffffffff),
EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT, (modifier >> 32),
EGL_NONE , EGL_NONE
};
if (!hasImportModifiers)
attribs[12] = attribs[13] =
attribs[14] = attribs[15] = EGL_NONE;
return g_egl_dynProcs.eglCreateImage(
this->display,
EGL_NO_CONTEXT,
EGL_LINUX_DMA_BUF_EXT,
(EGLClientBuffer)NULL,
attribs);
}
static bool egl_texDMABUFUpdate(EGL_Texture * texture,
const EGL_TexUpdate * update)
{
@@ -157,43 +222,36 @@ static bool egl_texDMABUFUpdate(EGL_Texture * texture,
break;
}
if (image == EGL_NO_IMAGE)
if (unlikely(image == EGL_NO_IMAGE))
{
const uint64_t modifier = DRM_FORMAT_MOD_LINEAR;
EGLAttrib attribs[] =
bool setup = false;
if (texture->format.pixFmt == EGL_PF_RGB_24 && has24BitSupport)
{
EGL_WIDTH , texture->format.width,
EGL_HEIGHT , texture->format.height,
EGL_LINUX_DRM_FOURCC_EXT , texture->format.fourcc,
EGL_DMA_BUF_PLANE0_FD_EXT , update->dmaFD,
EGL_DMA_BUF_PLANE0_OFFSET_EXT , 0,
EGL_DMA_BUF_PLANE0_PITCH_EXT , texture->format.stride,
EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, (modifier & 0xffffffff),
EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT, (modifier >> 32),
EGL_NONE , EGL_NONE
};
image = createImage(texture, update->dmaFD);
if (image == EGL_NO_IMAGE)
{
DEBUG_INFO("Using 24-bit in 32-bit for DMA");
has24BitSupport = false;
setup = true;
}
}
if (!this->hasImportModifiers)
attribs[12] = attribs[13] =
attribs[14] = attribs[15] = EGL_NONE;
image = g_egl_dynProcs.eglCreateImage(
this->display,
EGL_NO_CONTEXT,
EGL_LINUX_DMA_BUF_EXT,
(EGLClientBuffer)NULL,
attribs);
if (!has24BitSupport && setup)
texDMABUFSetup(texture);
if (image == EGL_NO_IMAGE)
image = createImage(texture, update->dmaFD);
if (unlikely(image == EGL_NO_IMAGE))
{
DEBUG_EGL_ERROR("Failed to create EGLImage for DMA transfer");
return false;
}
if (!vector_push(&this->images, &(struct FdImage) {
if (unlikely(!vector_push(&this->images, &(struct FdImage) {
.fd = update->dmaFD,
.image = image,
}))
})))
{
DEBUG_ERROR("Failed to store EGLImage");
g_egl_dynProcs.eglDestroyImage(this->display, image);
@@ -206,7 +264,7 @@ static bool egl_texDMABUFUpdate(EGL_Texture * texture,
glBindTexture(GL_TEXTURE_EXTERNAL_OES, parent->tex[parent->bufIndex]);
g_egl_dynProcs.glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, image);
if (parent->sync)
if (likely(parent->sync))
glDeleteSync(parent->sync);
parent->sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
@@ -220,9 +278,12 @@ static EGL_TexStatus egl_texDMABUFProcess(EGL_Texture * texture)
return EGL_TEX_STATUS_OK;
}
static EGL_TexStatus egl_texDMABUFGet(EGL_Texture * texture, GLuint * tex)
static EGL_TexStatus egl_texDMABUFGet(EGL_Texture * texture, GLuint * tex,
EGL_PixelFormat * fmt)
{
TextureBuffer * parent = UPCAST(TextureBuffer, texture);
TexDMABUF * this = UPCAST(TexDMABUF , parent);
GLsync sync = 0;
INTERLOCKED_SECTION(parent->copyLock,
@@ -265,6 +326,10 @@ static EGL_TexStatus egl_texDMABUFGet(EGL_Texture * texture, GLuint * tex)
}
*tex = parent->tex[parent->rIndex];
if (fmt)
*fmt = this->pixFmt;
return EGL_TEX_STATUS_OK;
}
@@ -273,7 +338,7 @@ static EGL_TexStatus egl_texDMABUFBind(EGL_Texture * texture)
GLuint tex;
EGL_TexStatus status;
if ((status = egl_texDMABUFGet(texture, &tex)) != EGL_TEX_STATUS_OK)
if ((status = egl_texDMABUFGet(texture, &tex, NULL)) != EGL_TEX_STATUS_OK)
return status;
glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex);

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* Copyright © 2017-2025 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -92,30 +92,60 @@ static bool egl_texFBUpdate(EGL_Texture * texture, const EGL_TexUpdate * update)
damage->count + update->rectCount > KVMFR_MAX_DAMAGE_RECTS;
if (damageAll)
framebuffer_read(
{
framebuffer_read(
update->frame,
parent->buf[parent->bufIndex].map,
texture->format.stride,
texture->format.pitch,
texture->format.height,
texture->format.width,
texture->format.bpp,
texture->format.stride
texture->format.pitch
);
}
else
{
memcpy(damage->rects + damage->count, update->rects,
update->rectCount * sizeof(FrameDamageRect));
damage->count += update->rectCount;
rectsFramebufferToBuffer(
damage->rects,
damage->count,
texture->format.bpp,
parent->buf[parent->bufIndex].map,
texture->format.stride,
texture->format.height,
update->frame,
texture->format.stride
);
if (texture->format.pixFmt == EGL_PF_BGR_32)
{
FrameDamageRect scaledDamageRects[damage->count];
for (int i = 0; i < damage->count; i++)
{
FrameDamageRect rect = damage->rects[i];
int originalX = rect.x;
int scaledX = originalX * 3 / 4;
rect.x = scaledX;
rect.width = (((originalX + rect.width) * 3 + 3) / 4) - scaledX;
scaledDamageRects[i] = rect;
}
rectsFramebufferToBuffer(
scaledDamageRects,
damage->count,
texture->format.bpp,
parent->buf[parent->bufIndex].map,
texture->format.pitch,
texture->format.height,
update->frame,
texture->format.pitch
);
}
else
{
rectsFramebufferToBuffer(
damage->rects,
damage->count,
texture->format.bpp,
parent->buf[parent->bufIndex].map,
texture->format.pitch,
texture->format.height,
update->frame,
texture->format.pitch
);
}
}
parent->buf[parent->bufIndex].updated = true;

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* Copyright © 2017-2025 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -30,6 +30,12 @@
bool egl_texUtilGetFormat(const EGL_TexSetup * setup, EGL_TexFormat * fmt)
{
fmt->pixFmt = setup->pixFmt;
fmt->width = setup->width;
fmt->height = setup->height;
fmt->stride = setup->stride;
fmt->pitch = setup->pitch;
switch(setup->pixFmt)
{
case EGL_PF_BGRA:
@@ -37,7 +43,7 @@ bool egl_texUtilGetFormat(const EGL_TexSetup * setup, EGL_TexFormat * fmt)
fmt->format = GL_BGRA_EXT;
fmt->intFormat = GL_BGRA_EXT;
fmt->dataType = GL_UNSIGNED_BYTE;
fmt->fourcc = DRM_FORMAT_ARGB8888;
fmt->fourcc = DRM_FORMAT_XRGB8888;
break;
case EGL_PF_RGBA:
@@ -45,7 +51,7 @@ bool egl_texUtilGetFormat(const EGL_TexSetup * setup, EGL_TexFormat * fmt)
fmt->format = GL_RGBA;
fmt->intFormat = GL_RGBA;
fmt->dataType = GL_UNSIGNED_BYTE;
fmt->fourcc = DRM_FORMAT_ABGR8888;
fmt->fourcc = DRM_FORMAT_XBGR8888;
break;
case EGL_PF_RGBA10:
@@ -53,7 +59,7 @@ bool egl_texUtilGetFormat(const EGL_TexSetup * setup, EGL_TexFormat * fmt)
fmt->format = GL_RGBA;
fmt->intFormat = GL_RGB10_A2;
fmt->dataType = GL_UNSIGNED_INT_2_10_10_10_REV;
fmt->fourcc = DRM_FORMAT_BGRA2101010;
fmt->fourcc = DRM_FORMAT_XBGR2101010;
break;
case EGL_PF_RGBA16F:
@@ -61,7 +67,25 @@ bool egl_texUtilGetFormat(const EGL_TexSetup * setup, EGL_TexFormat * fmt)
fmt->format = GL_RGBA;
fmt->intFormat = GL_RGBA16F;
fmt->dataType = GL_HALF_FLOAT;
fmt->fourcc = DRM_FORMAT_ABGR16161616F;
fmt->fourcc = DRM_FORMAT_XBGR16161616F;
break;
//EGL has no support for 24-bit formats, so we stuff it into a 32-bit
//texture to unpack with a shader later
case EGL_PF_BGR_32:
fmt->bpp = 4;
fmt->format = GL_BGRA_EXT;
fmt->intFormat = GL_BGRA_EXT;
fmt->dataType = GL_UNSIGNED_BYTE;
fmt->fourcc = DRM_FORMAT_ARGB8888;
break;
case EGL_PF_RGB_24:
fmt->bpp = 3;
fmt->format = GL_RGB;
fmt->intFormat = GL_BGRA_EXT;
fmt->dataType = GL_UNSIGNED_BYTE;
fmt->fourcc = DRM_FORMAT_RGB888;
break;
default:
@@ -69,22 +93,13 @@ bool egl_texUtilGetFormat(const EGL_TexSetup * setup, EGL_TexFormat * fmt)
return false;
}
fmt->pixFmt = setup->pixFmt;
fmt->width = setup->width;
fmt->height = setup->height;
if (!fmt->stride)
fmt->stride = setup->width;
if (setup->stride == 0)
{
fmt->stride = fmt->width * fmt->bpp;
fmt->pitch = fmt->width;
}
else
{
fmt->stride = setup->stride;
fmt->pitch = setup->stride / fmt->bpp;
}
if (!fmt->pitch)
fmt->pitch = fmt->stride * fmt->bpp;
fmt->bufferSize = fmt->height * fmt->stride;
fmt->dataSize = fmt->height * fmt->pitch;
return true;
}
@@ -95,12 +110,12 @@ bool egl_texUtilGenBuffers(const EGL_TexFormat * fmt, EGL_TexBuffer * buffers,
{
EGL_TexBuffer *buffer = &buffers[i];
buffer->size = fmt->bufferSize;
buffer->size = fmt->dataSize;
glGenBuffers(1, &buffer->pbo);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer->pbo);
g_egl_dynProcs.glBufferStorageEXT(
GL_PIXEL_UNPACK_BUFFER,
fmt->bufferSize,
fmt->dataSize,
NULL,
GL_MAP_WRITE_BIT |
GL_MAP_PERSISTENT_BIT_EXT |

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* Copyright © 2017-2025 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -33,8 +33,8 @@ typedef struct EGL_TexFormat
GLenum intFormat;
GLenum dataType;
unsigned int fourcc;
size_t bufferSize;
size_t dataSize;
size_t width , height;
size_t stride, pitch;
}
@@ -62,10 +62,13 @@ void egl_texUtilUnmapBuffer(EGL_TexBuffer * buffer);
*/
#define fourcc_code(a, b, c, d) ((uint32_t)(a) | ((uint32_t)(b) << 8) | \
((uint32_t)(c) << 16) | ((uint32_t)(d) << 24))
#define DRM_FORMAT_RGB888 fourcc_code('R', 'G', '2', '4')
#define DRM_FORMAT_ARGB8888 fourcc_code('A', 'R', '2', '4')
#define DRM_FORMAT_ABGR8888 fourcc_code('A', 'B', '2', '4')
#define DRM_FORMAT_BGRA2101010 fourcc_code('A', 'B', '3', '0')
#define DRM_FORMAT_ABGR16161616F fourcc_code('A', 'B', '4', 'H')
#define DRM_FORMAT_XRGB8888 fourcc_code('X', 'R', '2', '4')
#define DRM_FORMAT_XBGR8888 fourcc_code('X', 'B', '2', '4')
#define DRM_FORMAT_XBGR2101010 fourcc_code('X', 'B', '3', '0')
#define DRM_FORMAT_XBGR16161616F fourcc_code('X', 'B', '4', 'H')
#define DRM_FORMAT_MOD_VENDOR_NONE 0
#define fourcc_mod_code(vendor, val) \

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.0)
cmake_minimum_required(VERSION 3.10)
project(renderer_Opengl LANGUAGES C CXX)
find_package(PkgConfig)

View File

@@ -1,6 +1,6 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* Copyright © 2017-2025 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
@@ -84,10 +84,10 @@ struct IntPoint
int y;
};
struct IntRect
struct MouseRect
{
int x;
int y;
float x;
float y;
int w;
int h;
};
@@ -124,6 +124,7 @@ struct Inst
GLuint dataFormat;
size_t texSize;
size_t texPos;
float scaleX, scaleY;
const FrameBuffer * frame;
uint64_t drawStart;
@@ -157,7 +158,7 @@ struct Inst
bool newShape;
LG_RendererCursor mouseType;
bool mouseVisible;
struct IntRect mousePos;
struct MouseRect mousePos;
};
static bool _checkGLError(unsigned int line, const char * name);
@@ -356,12 +357,17 @@ bool opengl_onMouseEvent(LG_Renderer * renderer, const bool visible,
{
struct Inst * this = UPCAST(struct Inst, renderer);
if (this->mousePos.x == x && this->mousePos.y == y && this->mouseVisible == visible)
float fx = (float)x * this->scaleX;
float fy = (float)y * this->scaleY;
if (this->mousePos.x == fx &&
this->mousePos.y == fy &&
this->mouseVisible == visible)
return true;
this->mouseVisible = visible;
this->mousePos.x = x;
this->mousePos.y = y;
this->mousePos.x = fx;
this->mousePos.y = fy;
this->mouseUpdate = true;
return false;
}
@@ -372,6 +378,10 @@ bool opengl_onFrameFormat(LG_Renderer * renderer, const LG_RendererFormat format
LG_LOCK(this->formatLock);
memcpy(&this->format, &format, sizeof(LG_RendererFormat));
this->scaleX = (float)this->format.frameWidth / this->format.screenWidth;
this->scaleY = (float)this->format.frameHeight / this->format.screenHeight;
this->reconfigure = true;
LG_UNLOCK(this->formatLock);
return true;
@@ -612,13 +622,13 @@ static void opengl_spiceDrawFill(LG_Renderer * renderer, int x, int y, int width
glBindTexture(GL_TEXTURE_2D, this->textures[SPICE_TEXTURE]);
glPixelStorei(GL_UNPACK_ALIGNMENT , 4 );
glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
for(; y < height; ++y)
for(int dy = 0; dy < height; ++dy)
glTexSubImage2D
(
GL_TEXTURE_2D,
0 ,
x ,
y ,
y + dy ,
width ,
1 ,
GL_BGRA,
@@ -777,13 +787,33 @@ static enum ConfigStatus configure(struct Inst * this)
this->dataFormat = GL_HALF_FLOAT;
break;
case FRAME_TYPE_RGB_24:
this->intFormat = GL_RGB8;
this->vboFormat = GL_RGB;
this->dataFormat = GL_UNSIGNED_BYTE;
break;
case FRAME_TYPE_BGR_32:
this->intFormat = GL_RGB8;
this->vboFormat = GL_BGR;
this->dataFormat = GL_UNSIGNED_BYTE;
/* The data that the host returns is comes from a 32-bit RBGA texture,
* as OpenGL supports BGR directly we need to correct dimensions in order
* to make this happen.
*/
this->format.dataWidth = this->format.frameWidth;
this->format.dataHeight = this->format.frameHeight;
this->format.bpp = 24;
break;
default:
DEBUG_ERROR("Unknown/unsupported compression type");
return CONFIG_STATUS_ERROR;
}
// calculate the texture size in bytes
this->texSize = this->format.frameHeight * this->format.pitch;
this->texSize = this->format.dataHeight * this->format.pitch;
this->texPos = 0;
g_gl_dynProcs.glGenBuffers(BUFFER_COUNT, this->vboID);
@@ -797,10 +827,10 @@ static enum ConfigStatus configure(struct Inst * this)
if (this->amdPinnedMemSupport)
{
const int pagesize = getpagesize();
for(int i = 0; i < BUFFER_COUNT; ++i)
{
this->texPixels[i] = aligned_alloc(pagesize, this->texSize);
this->texPixels[i] = aligned_alloc(pagesize,
ALIGN_TO(this->texSize, pagesize));
if (!this->texPixels[i])
{
DEBUG_ERROR("Failed to allocate memory for texture");
@@ -809,7 +839,8 @@ static enum ConfigStatus configure(struct Inst * this)
memset(this->texPixels[i], 0, this->texSize);
g_gl_dynProcs.glBindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, this->vboID[i]);
g_gl_dynProcs.glBindBuffer(
GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, this->vboID[i]);
if (check_gl_error("glBindBuffer"))
{
LG_UNLOCK(this->formatLock);
@@ -1115,7 +1146,9 @@ static bool opengl_bufferFn(void * opaque, const void * data, size_t size)
size,
data
);
check_gl_error("glBufferSubData");
if (check_gl_error("glBufferSubData"))
return false;
this->texPos += size;
return true;
@@ -1162,16 +1195,15 @@ static bool drawFrame(struct Inst * this)
glBindTexture(GL_TEXTURE_2D, this->frames[this->texWIndex]);
g_gl_dynProcs.glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->vboID[this->texWIndex]);
const int bpp = this->format.bpp / 8;
glPixelStorei(GL_UNPACK_ALIGNMENT , bpp);
int bpp = this->format.bpp / 8;
glPixelStorei(GL_UNPACK_ALIGNMENT , bpp < 4 ? 1 : bpp);
glPixelStorei(GL_UNPACK_ROW_LENGTH, this->format.frameWidth);
this->texPos = 0;
framebuffer_read_fn(
this->frame,
this->format.frameHeight,
this->format.frameWidth,
this->format.dataHeight,
this->format.dataWidth,
bpp,
this->format.pitch,
opengl_bufferFn,
@@ -1194,9 +1226,17 @@ static bool drawFrame(struct Inst * this)
);
if (check_gl_error("glTexSubImage2D"))
{
DEBUG_ERROR("texWIndex: %u, width: %u, height: %u, vboFormat: %x, texSize: %lu",
this->texWIndex, this->format.frameWidth, this->format.frameHeight,
this->vboFormat, this->texSize
DEBUG_ERROR(
"texWIndex: %u, "
"width: %u, "
"height: %u, "
"vboFormat: %x, "
"texSize: %lu",
this->texWIndex,
this->format.frameWidth,
this->format.frameHeight,
this->vboFormat,
this->texSize
);
}

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