mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-06-16 03:34:27 +00:00
Compare commits
155 Commits
dmabuf-tes
...
dxgi-rgb24
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e31874b809 | ||
|
|
a2443cf926 | ||
|
|
eaaef65791 | ||
|
|
11542d7ace | ||
|
|
138a0aee53 | ||
|
|
7a30736ac4 | ||
|
|
174b51b144 | ||
|
|
aa9dbe654d | ||
|
|
d592f13f88 | ||
|
|
905fea57f0 | ||
|
|
3a6afd04d2 | ||
|
|
c0e09e13a5 | ||
|
|
3843afa927 | ||
|
|
49bdf046fe | ||
|
|
8605df8c8d | ||
|
|
d847c2c144 | ||
|
|
6492c47e1e | ||
|
|
86e8e99107 | ||
|
|
dcde981a17 | ||
|
|
c54a09ca25 | ||
|
|
5bba4dfab5 | ||
|
|
3af2cf54d6 | ||
|
|
4aba15f31c | ||
|
|
a455078e0f | ||
|
|
f8586fd063 | ||
|
|
ad13928c73 | ||
|
|
f991f994f0 | ||
|
|
772e0e3b4a | ||
|
|
fd79bb1333 | ||
|
|
d6519c4486 | ||
|
|
9fefbae749 | ||
|
|
fa561c121e | ||
|
|
c2e3c37bab | ||
|
|
54bd08c3cb | ||
|
|
eb2796d40b | ||
|
|
748c9c177e | ||
|
|
cc48257aeb | ||
|
|
3838e1f996 | ||
|
|
881aa9e179 | ||
|
|
9a2638bfa0 | ||
|
|
8d7d5ba8fd | ||
|
|
09b6fee360 | ||
|
|
561c45bcb9 | ||
|
|
5f613b09d6 | ||
|
|
30c577beeb | ||
|
|
6c7f3c4197 | ||
|
|
139e98ac3b | ||
|
|
d02e3730b2 | ||
|
|
ea5b6b4026 | ||
|
|
6329779893 | ||
|
|
1da50d220e | ||
|
|
3106d0e3e2 | ||
|
|
d44fc36fc4 | ||
|
|
c29404eea6 | ||
|
|
c665044bfa | ||
|
|
578d98fd22 | ||
|
|
b3879ff1d7 | ||
|
|
f6b2cec841 | ||
|
|
626f5eb32e | ||
|
|
29c797d7b6 | ||
|
|
3625207801 | ||
|
|
25d6dd3ba2 | ||
|
|
1e30539fb2 | ||
|
|
52410beea7 | ||
|
|
c591f7a8ae | ||
|
|
21cd380cad | ||
|
|
e225f66cee | ||
|
|
2206752b66 | ||
|
|
0510d06c4b | ||
|
|
699d95818d | ||
|
|
fffac35300 | ||
|
|
35b0f8edf3 | ||
|
|
544164f637 | ||
|
|
b94166177f | ||
|
|
69b984aa2c | ||
|
|
c100df4037 | ||
|
|
47329ebd89 | ||
|
|
5d7469d23e | ||
|
|
6625cd733a | ||
|
|
b41840b010 | ||
|
|
2f36aaff5c | ||
|
|
200b7b732c | ||
|
|
eeea24ebfb | ||
|
|
54066094bd | ||
|
|
c5923b9b4d | ||
|
|
bde2eef175 | ||
|
|
e0bdd869d6 | ||
|
|
ccd0a0bcf9 | ||
|
|
742e41c2c3 | ||
|
|
3ed71a09f4 | ||
|
|
12d051d8c0 | ||
|
|
a6a6b8779a | ||
|
|
ad65561511 | ||
|
|
6b65c7e339 | ||
|
|
646f5b1be8 | ||
|
|
128a8938c6 | ||
|
|
2e515657dd | ||
|
|
1cf8e8c846 | ||
|
|
df5c648377 | ||
|
|
78df2073ff | ||
|
|
844a37a276 | ||
|
|
e658c2e0a2 | ||
|
|
b2ec60d2dc | ||
|
|
e6aa2b85a9 | ||
|
|
a3045e0b4a | ||
|
|
9cadb64942 | ||
|
|
82607a7d6f | ||
|
|
8d90c9c2a5 | ||
|
|
24d4fce17c | ||
|
|
8dba4b6c0b | ||
|
|
193977895b | ||
|
|
219c73edbe | ||
|
|
6522920ea1 | ||
|
|
e32b292cc1 | ||
|
|
53525847fd | ||
|
|
9d66a68403 | ||
|
|
07bcc54732 | ||
|
|
dab5618a6d | ||
|
|
ad43969c1a | ||
|
|
99333a03c1 | ||
|
|
45318aa653 | ||
|
|
f84165ac66 | ||
|
|
e4a8424fad | ||
|
|
880d8042a4 | ||
|
|
a629d24dc3 | ||
|
|
7c1bb13d70 | ||
|
|
9d5c543a53 | ||
|
|
063a859de1 | ||
|
|
4f4cf2be7d | ||
|
|
9759b5aa8f | ||
|
|
bbd0c7a99b | ||
|
|
c11748a76f | ||
|
|
d6b26b0eb1 | ||
|
|
fd0cc6aa10 | ||
|
|
80b9bda59d | ||
|
|
0c176acf94 | ||
|
|
0c3dce3ca6 | ||
|
|
3c85957b99 | ||
|
|
77ddcfe489 | ||
|
|
d228ef135e | ||
|
|
0afcf2c2ce | ||
|
|
75da66a090 | ||
|
|
11676d3d56 | ||
|
|
b13682a9ef | ||
|
|
642634293d | ||
|
|
01f9c2bfb5 | ||
|
|
9385b2de7a | ||
|
|
d2f7667fae | ||
|
|
cfef966603 | ||
|
|
4f09d5b771 | ||
|
|
b7b302334c | ||
|
|
28e74a73a4 | ||
|
|
996e1b2f7a | ||
|
|
0ee5751b3a | ||
|
|
e067db7bb4 |
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
@@ -1,4 +1,4 @@
|
||||
# Jonathan Rubenstein (JJRcop)
|
||||
# - Primary documentation manager. Does not require direct approval for every
|
||||
# - change, but should be consulted for large additions and changes.
|
||||
docs/ jrubcop@gmail.com
|
||||
/doc/ jrubcop@gmail.com
|
||||
|
||||
6
.github/workflows/build.yml
vendored
6
.github/workflows/build.yml
vendored
@@ -97,7 +97,7 @@ jobs:
|
||||
make -j$(nproc)
|
||||
|
||||
host-windows-cross:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
@@ -183,8 +183,8 @@ jobs:
|
||||
sudo apt-get update
|
||||
- name: Install docs dependencies
|
||||
run: |
|
||||
sudo apt-get install python3-sphinx python3-sphinx-rtd-theme
|
||||
sudo pip3 install sphinxcontrib-spelling
|
||||
sudo apt-get install python3-sphinx python3-sphinx-rtd-theme \
|
||||
python3-sphinxcontrib.spelling
|
||||
- name: Build docs
|
||||
run: |
|
||||
cd doc
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -10,3 +10,8 @@ module/modules.order
|
||||
*/build
|
||||
__pycache__
|
||||
*.py[co]
|
||||
*/.vs
|
||||
idd/Debug
|
||||
idd/x64
|
||||
idd/LGIdd/x64
|
||||
idd/LGIdd/Debug
|
||||
|
||||
2
AUTHORS
2
AUTHORS
@@ -65,3 +65,5 @@ Leonard Fricke <leonard.fricke98@gmail.com> (Leo1998)
|
||||
David Meier <meier_david_91@hotmail.com> (Kenny.ch)
|
||||
Daniel Cordero <looking-glass@0xdc.io> (0xdc)
|
||||
esi <git@esibun.net> (esibun)
|
||||
MakiseKurisu <saberconer@gmail.com> (MakiseKurisu)
|
||||
Zenithal <i@zenithal.me> (ZenithalHourlyRate)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(looking-glass-client C CXX)
|
||||
|
||||
get_filename_component(PROJECT_TOP "${PROJECT_SOURCE_DIR}/.." ABSOLUTE)
|
||||
@@ -45,12 +45,6 @@ add_feature_info(ENABLE_UBSAN ENABLE_UBSAN "UndefinedBehaviorSanitizer support."
|
||||
option(ENABLE_X11 "Build with X11 support" ON)
|
||||
add_feature_info(ENABLE_X11 ENABLE_X11 "X11 support.")
|
||||
|
||||
option(ENABLE_WAYLAND "Build with Wayland support" ON)
|
||||
add_feature_info(ENABLE_WAYLAND ENABLE_WAYLAND "Wayland support.")
|
||||
|
||||
option(ENABLE_LIBDECOR "Build with libdecor support" OFF)
|
||||
add_feature_info(ENABLE_LIBDECOR ENABLE_LIBDECOR "libdecor support.")
|
||||
|
||||
option(ENABLE_PIPEWIRE "Build with PipeWire audio output support" ON)
|
||||
add_feature_info(ENABLE_PIPEWIRE ENABLE_PIPEWIRE "PipeWire audio support.")
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(audiodevs LANGUAGES C)
|
||||
|
||||
set(AUDIODEV_H "${CMAKE_BINARY_DIR}/include/dynamic/audiodev.h")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(audiodev_PipeWire LANGUAGES C)
|
||||
|
||||
find_package(PkgConfig)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(audiodev_PulseAudio LANGUAGES C)
|
||||
|
||||
find_package(PkgConfig)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(displayservers LANGUAGES C)
|
||||
|
||||
set(DISPLAYSERVER_H "${CMAKE_BINARY_DIR}/include/dynamic/displayservers.h")
|
||||
@@ -18,6 +18,9 @@ function(add_displayserver name)
|
||||
add_subdirectory(${name})
|
||||
endfunction()
|
||||
|
||||
option(ENABLE_WAYLAND "Build with Wayland support" ON)
|
||||
add_feature_info(ENABLE_WAYLAND ENABLE_WAYLAND "Wayland support.")
|
||||
|
||||
# Add/remove displayservers here!
|
||||
if (ENABLE_WAYLAND)
|
||||
add_displayserver(Wayland)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(displayserver_Wayland LANGUAGES C)
|
||||
|
||||
find_package(PkgConfig)
|
||||
@@ -8,19 +8,7 @@ pkg_check_modules(DISPLAYSERVER_Wayland REQUIRED IMPORTED_TARGET
|
||||
xkbcommon
|
||||
)
|
||||
|
||||
set(DISPLAYSERVER_Wayland_OPT_PKGCONFIG_LIBRARIES "")
|
||||
set(displayserver_Wayland_SHELL_SRC "")
|
||||
|
||||
if (ENABLE_LIBDECOR)
|
||||
pkg_check_modules(DISPLAYSERVER_Wayland_LIBDECOR REQUIRED IMPORTED_TARGET
|
||||
libdecor-0
|
||||
)
|
||||
list(APPEND DISPLAYSERVER_Wayland_OPT_PKGCONFIG_LIBRARIES PkgConfig::DISPLAYSERVER_Wayland_LIBDECOR)
|
||||
list(APPEND displayserver_Wayland_SHELL_SRC shell_libdecor.c)
|
||||
add_compile_definitions(ENABLE_LIBDECOR)
|
||||
else()
|
||||
list(APPEND displayserver_Wayland_SHELL_SRC shell_xdg.c)
|
||||
endif()
|
||||
find_program(WAYLAND_SCANNER_EXECUTABLE NAMES wayland-scanner)
|
||||
|
||||
add_library(displayserver_Wayland STATIC
|
||||
activation.c
|
||||
@@ -36,66 +24,19 @@ add_library(displayserver_Wayland STATIC
|
||||
registry.c
|
||||
wayland.c
|
||||
window.c
|
||||
${displayserver_Wayland_SHELL_SRC}
|
||||
)
|
||||
|
||||
add_subdirectory(protocol)
|
||||
add_subdirectory(desktops)
|
||||
|
||||
target_link_libraries(displayserver_Wayland
|
||||
PkgConfig::DISPLAYSERVER_Wayland
|
||||
${DISPLAYSERVER_Wayland_OPT_PKGCONFIG_LIBRARIES}
|
||||
lg_common
|
||||
wayland_protocol
|
||||
wayland_desktops
|
||||
)
|
||||
|
||||
target_include_directories(displayserver_Wayland
|
||||
PRIVATE
|
||||
src
|
||||
.
|
||||
)
|
||||
|
||||
find_program(WAYLAND_SCANNER_EXECUTABLE NAMES wayland-scanner)
|
||||
|
||||
macro(wayland_generate protocol_file output_file)
|
||||
add_custom_command(OUTPUT "${output_file}.h"
|
||||
COMMAND "${WAYLAND_SCANNER_EXECUTABLE}" client-header "${protocol_file}" "${output_file}.h"
|
||||
DEPENDS "${protocol_file}"
|
||||
VERBATIM)
|
||||
|
||||
add_custom_command(OUTPUT "${output_file}.c"
|
||||
COMMAND "${WAYLAND_SCANNER_EXECUTABLE}" private-code "${protocol_file}" "${output_file}.c"
|
||||
DEPENDS "${protocol_file}"
|
||||
VERBATIM)
|
||||
|
||||
target_sources(displayserver_Wayland PRIVATE "${output_file}.h" "${output_file}.c")
|
||||
endmacro()
|
||||
|
||||
set(WAYLAND_PROTOCOLS_BASE "${PROJECT_TOP}/repos/wayland-protocols")
|
||||
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/wayland")
|
||||
include_directories("${CMAKE_BINARY_DIR}/wayland")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/stable/xdg-shell/xdg-shell.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-xdg-shell-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/stable/presentation-time/presentation-time.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-presentation-time-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/stable/viewporter/viewporter.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-viewporter-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-xdg-decoration-unstable-v1-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/unstable/relative-pointer/relative-pointer-unstable-v1.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-relative-pointer-unstable-v1-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-pointer-constraints-unstable-v1-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-keyboard-shortcuts-inhibit-unstable-v1-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-idle-inhibit-unstable-v1-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/unstable/xdg-output/xdg-output-unstable-v1.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-xdg-output-unstable-v1-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/staging/xdg-activation/xdg-activation-v1.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-xdg-activation-v1-client-protocol")
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
58
client/displayservers/Wayland/desktops/CMakeLists.txt
Normal file
58
client/displayservers/Wayland/desktops/CMakeLists.txt
Normal file
@@ -0,0 +1,58 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(wayland_desktops LANGUAGES C)
|
||||
|
||||
set(DESKTOP_H "${CMAKE_BINARY_DIR}/include/dynamic/wayland_desktops.h")
|
||||
set(DESKTOP_C "${CMAKE_BINARY_DIR}/src/wayland_desktops.c")
|
||||
|
||||
file(WRITE ${DESKTOP_H} "#include \"interface/desktop.h\"\n\n")
|
||||
file(APPEND ${DESKTOP_H} "extern struct WL_DesktopOps * WL_Desktops[];\n\n")
|
||||
|
||||
file(WRITE ${DESKTOP_C} "#include \"interface/desktop.h\"\n\n")
|
||||
file(APPEND ${DESKTOP_C} "#include <stddef.h>\n\n")
|
||||
|
||||
set(DESKTOPS "_")
|
||||
set(DESKTOPS_LINK "_")
|
||||
function(add_desktop name)
|
||||
set(DESKTOPS "${DESKTOPS};${name}" PARENT_SCOPE)
|
||||
set(DESKTOPS_LINK "${DESKTOPS_LINK};wayland_desktop_${name}" PARENT_SCOPE)
|
||||
add_subdirectory(${name})
|
||||
endfunction()
|
||||
|
||||
# Add/remove desktops here!
|
||||
|
||||
# the first entry here is the default
|
||||
add_desktop(xdg)
|
||||
|
||||
pkg_check_modules(LIBDECOR IMPORTED_TARGET libdecor-0)
|
||||
if(LIBDECOR_FOUND)
|
||||
option(ENABLE_LIBDECOR "Build with libdecor support" ON)
|
||||
else()
|
||||
option(ENABLE_LIBDECOR "Build with libdecor support" OFF)
|
||||
endif()
|
||||
add_feature_info(ENABLE_LIBDECOR ENABLE_LIBDECOR "libdecor support.")
|
||||
if (ENABLE_LIBDECOR)
|
||||
add_desktop(libdecor)
|
||||
endif()
|
||||
|
||||
list(REMOVE_AT DESKTOPS 0)
|
||||
list(REMOVE_AT DESKTOPS_LINK 0)
|
||||
|
||||
list(LENGTH DESKTOPS DESKTOP_COUNT)
|
||||
file(APPEND ${DESKTOP_H} "#define WL_DESKTOP_COUNT ${DESKTOP_COUNT}\n")
|
||||
|
||||
foreach(desktop ${DESKTOPS})
|
||||
file(APPEND ${DESKTOP_C} "extern struct WL_DesktopOps WLD_${desktop};\n")
|
||||
endforeach()
|
||||
|
||||
file(APPEND ${DESKTOP_C} "\nconst struct WL_DesktopOps * WL_Desktops[] =\n{\n")
|
||||
foreach(desktop ${DESKTOPS})
|
||||
file(APPEND ${DESKTOP_C} " &WLD_${desktop},\n")
|
||||
endforeach()
|
||||
file(APPEND ${DESKTOP_C} " NULL\n};")
|
||||
|
||||
add_library(wayland_desktops STATIC ${DESKTOP_C})
|
||||
target_link_libraries(wayland_desktops ${DESKTOPS_LINK})
|
||||
target_include_directories(wayland_desktops
|
||||
PRIVATE
|
||||
../
|
||||
)
|
||||
@@ -0,0 +1,16 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(wayland_desktop_libdecor LANGUAGES C)
|
||||
|
||||
add_library(wayland_desktop_libdecor STATIC
|
||||
libdecor.c
|
||||
)
|
||||
|
||||
target_link_libraries(wayland_desktop_libdecor
|
||||
lg_common
|
||||
wayland_protocol
|
||||
PkgConfig::LIBDECOR
|
||||
)
|
||||
|
||||
include_directories(
|
||||
"../../"
|
||||
)
|
||||
269
client/displayservers/Wayland/desktops/libdecor/libdecor.c
Normal file
269
client/displayservers/Wayland/desktops/libdecor/libdecor.c
Normal file
@@ -0,0 +1,269 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "interface/desktop.h"
|
||||
#include "wayland-xdg-shell-client-protocol.h"
|
||||
|
||||
#include "wayland.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <sys/epoll.h>
|
||||
|
||||
#include <libdecor.h>
|
||||
#include <wayland-client.h>
|
||||
|
||||
#include "app.h"
|
||||
#include "common/debug.h"
|
||||
|
||||
// Maximum number of fds we can process at once in waylandWait
|
||||
#define MAX_EPOLL_EVENTS 10
|
||||
|
||||
typedef struct LibDecorState
|
||||
{
|
||||
bool configured;
|
||||
struct libdecor * libdecor;
|
||||
struct libdecor_frame * libdecorFrame;
|
||||
|
||||
int32_t width, height;
|
||||
bool needsResize;
|
||||
bool fullscreen;
|
||||
uint32_t resizeSerial;
|
||||
}
|
||||
LibDecorState;
|
||||
|
||||
static LibDecorState state = {0};
|
||||
|
||||
struct libdecor_configuration
|
||||
{
|
||||
uint32_t serial;
|
||||
|
||||
bool has_window_state;
|
||||
enum libdecor_window_state window_state;
|
||||
|
||||
bool has_size;
|
||||
int window_width;
|
||||
int window_height;
|
||||
};
|
||||
|
||||
static void libdecorHandleError(struct libdecor * context, enum libdecor_error error,
|
||||
const char *message)
|
||||
{
|
||||
DEBUG_ERROR("Got libdecor error (%d): %s", error, message);
|
||||
}
|
||||
|
||||
static void libdecorFrameConfigure(struct libdecor_frame * frame,
|
||||
struct libdecor_configuration * configuration, void * opaque)
|
||||
{
|
||||
if (!state.configured)
|
||||
{
|
||||
xdg_surface_ack_configure(libdecor_frame_get_xdg_surface(frame), configuration->serial);
|
||||
state.configured = true;
|
||||
return;
|
||||
}
|
||||
|
||||
int width, height;
|
||||
if (libdecor_configuration_get_content_size(configuration, frame, &width, &height))
|
||||
{
|
||||
state.width = width;
|
||||
state.height = height;
|
||||
|
||||
struct libdecor_state * s = libdecor_state_new(width, height);
|
||||
libdecor_frame_commit(state.libdecorFrame, s, NULL);
|
||||
libdecor_state_free(s);
|
||||
}
|
||||
|
||||
enum libdecor_window_state windowState;
|
||||
if (libdecor_configuration_get_window_state(configuration, &windowState))
|
||||
state.fullscreen = windowState & LIBDECOR_WINDOW_STATE_FULLSCREEN;
|
||||
|
||||
state.resizeSerial = configuration->serial;
|
||||
waylandNeedsResize();
|
||||
}
|
||||
|
||||
static void libdecorFrameClose(struct libdecor_frame * frame, void * opaque)
|
||||
{
|
||||
app_handleCloseEvent();
|
||||
}
|
||||
|
||||
static void libdecorFrameCommit(struct libdecor_frame * frame, void * opaque)
|
||||
{
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
|
||||
static struct libdecor_interface libdecorListener =
|
||||
{
|
||||
libdecorHandleError,
|
||||
};
|
||||
|
||||
static struct libdecor_frame_interface libdecorFrameListener =
|
||||
{
|
||||
libdecorFrameConfigure,
|
||||
libdecorFrameClose,
|
||||
libdecorFrameCommit,
|
||||
};
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
static void libdecorCallback(uint32_t events, void * opaque)
|
||||
{
|
||||
libdecor_dispatch(state.libdecor, 0);
|
||||
}
|
||||
|
||||
static bool libdecor_shellInit(
|
||||
struct wl_display * display, struct wl_surface * surface,
|
||||
const char * title, bool fullscreen,
|
||||
bool maximize, bool borderless, bool resizable)
|
||||
{
|
||||
state.libdecor = libdecor_new(display, &libdecorListener);
|
||||
state.libdecorFrame = libdecor_decorate(state.libdecor, surface,
|
||||
&libdecorFrameListener, NULL);
|
||||
|
||||
libdecor_frame_set_app_id(state.libdecorFrame, "looking-glass-client");
|
||||
libdecor_frame_set_title(state.libdecorFrame, title);
|
||||
libdecor_frame_map(state.libdecorFrame);
|
||||
|
||||
if (resizable)
|
||||
libdecor_frame_set_capabilities(state.libdecorFrame,
|
||||
LIBDECOR_ACTION_RESIZE);
|
||||
else
|
||||
libdecor_frame_unset_capabilities(state.libdecorFrame,
|
||||
LIBDECOR_ACTION_RESIZE);
|
||||
|
||||
while (!state.configured)
|
||||
libdecor_dispatch(state.libdecor, 0);
|
||||
|
||||
if (!waylandPollRegister(libdecor_get_fd(state.libdecor),
|
||||
libdecorCallback, NULL, EPOLLIN))
|
||||
{
|
||||
DEBUG_ERROR("Failed register display to epoll: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void libdecor_shellAckConfigureIfNeeded(void)
|
||||
{
|
||||
if (state.resizeSerial)
|
||||
{
|
||||
xdg_surface_ack_configure(
|
||||
libdecor_frame_get_xdg_surface(state.libdecorFrame), state.resizeSerial);
|
||||
state.resizeSerial = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void libdecor_setFullscreen(bool fs)
|
||||
{
|
||||
if (fs)
|
||||
libdecor_frame_set_fullscreen(state.libdecorFrame, NULL);
|
||||
else
|
||||
libdecor_frame_unset_fullscreen(state.libdecorFrame);
|
||||
|
||||
libdecor_frame_set_visibility(state.libdecorFrame, !fs);
|
||||
}
|
||||
|
||||
static bool libdecor_getFullscreen(void)
|
||||
{
|
||||
return state.fullscreen;
|
||||
}
|
||||
|
||||
static void libdecor_minimize(void)
|
||||
{
|
||||
libdecor_frame_set_minimized(state.libdecorFrame);
|
||||
}
|
||||
|
||||
static void libdecor_shellResize(int w, int h)
|
||||
{
|
||||
if (!libdecor_frame_is_floating(state.libdecorFrame))
|
||||
return;
|
||||
|
||||
state.width = w;
|
||||
state.height = h;
|
||||
|
||||
struct libdecor_state * s = libdecor_state_new(w, h);
|
||||
libdecor_frame_commit(state.libdecorFrame, s, NULL);
|
||||
libdecor_state_free(s);
|
||||
|
||||
waylandNeedsResize();
|
||||
}
|
||||
|
||||
static void libdecor_setSize(int w, int h)
|
||||
{
|
||||
state.width = w;
|
||||
state.height = h;
|
||||
}
|
||||
|
||||
static void libdecor_getSize(int * w, int * h)
|
||||
{
|
||||
*w = state.width;
|
||||
*h = state.height;
|
||||
}
|
||||
|
||||
static bool libdecor_registryGlobalHandler(void * data,
|
||||
struct wl_registry * registry, uint32_t name, const char * interface,
|
||||
uint32_t version)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool libdecor_pollInit(struct wl_display * display)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void libdecor_pollWait(struct wl_display * display, int epollFd,
|
||||
unsigned int time)
|
||||
{
|
||||
libdecor_dispatch(state.libdecor, 0);
|
||||
|
||||
struct epoll_event events[MAX_EPOLL_EVENTS];
|
||||
int count;
|
||||
if ((count = epoll_wait(epollFd, events, MAX_EPOLL_EVENTS, time)) < 0)
|
||||
{
|
||||
if (errno != EINTR)
|
||||
DEBUG_INFO("epoll failed: %s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
struct WaylandPoll * poll = events[i].data.ptr;
|
||||
if (!poll->removed)
|
||||
poll->callback(events[i].events, poll->opaque);
|
||||
}
|
||||
}
|
||||
|
||||
WL_DesktopOps WLD_libdecor =
|
||||
{
|
||||
.name = "libdecor",
|
||||
.compositor = "gnome-shell",
|
||||
.shellInit = libdecor_shellInit,
|
||||
.shellAckConfigureIfNeeded = libdecor_shellAckConfigureIfNeeded,
|
||||
.setFullscreen = libdecor_setFullscreen,
|
||||
.getFullscreen = libdecor_getFullscreen,
|
||||
.minimize = libdecor_minimize,
|
||||
.shellResize = libdecor_shellResize,
|
||||
.setSize = libdecor_setSize,
|
||||
.getSize = libdecor_getSize,
|
||||
.registryGlobalHandler = libdecor_registryGlobalHandler,
|
||||
.pollInit = libdecor_pollInit,
|
||||
.pollWait = libdecor_pollWait
|
||||
};
|
||||
15
client/displayservers/Wayland/desktops/xdg/CMakeLists.txt
Normal file
15
client/displayservers/Wayland/desktops/xdg/CMakeLists.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(wayland_desktop_xdg LANGUAGES C)
|
||||
|
||||
add_library(wayland_desktop_xdg STATIC
|
||||
xdg.c
|
||||
)
|
||||
|
||||
target_link_libraries(wayland_desktop_xdg
|
||||
lg_common
|
||||
wayland_protocol
|
||||
)
|
||||
|
||||
include_directories(
|
||||
"../../"
|
||||
)
|
||||
314
client/displayservers/Wayland/desktops/xdg/xdg.c
Normal file
314
client/displayservers/Wayland/desktops/xdg/xdg.c
Normal file
@@ -0,0 +1,314 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "wayland.h"
|
||||
#include "wayland-xdg-shell-client-protocol.h"
|
||||
#include "wayland-xdg-decoration-unstable-v1-client-protocol.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <wayland-client.h>
|
||||
|
||||
#include "app.h"
|
||||
#include "common/debug.h"
|
||||
|
||||
// Maximum number of fds we can process at once in waylandWait
|
||||
#define MAX_EPOLL_EVENTS 10
|
||||
|
||||
typedef struct XDGState
|
||||
{
|
||||
bool configured;
|
||||
|
||||
struct xdg_wm_base * wmBase;
|
||||
struct xdg_surface * surface;
|
||||
struct xdg_toplevel * toplevel;
|
||||
struct zxdg_decoration_manager_v1 * decorationManager;
|
||||
struct zxdg_toplevel_decoration_v1 * toplevelDecoration;
|
||||
|
||||
int32_t width, height;
|
||||
uint32_t resizeSerial;
|
||||
bool fullscreen;
|
||||
bool floating;
|
||||
int displayFd;
|
||||
}
|
||||
XDGState;
|
||||
|
||||
static XDGState state = {0};
|
||||
|
||||
// XDG WM base listeners.
|
||||
|
||||
static void xdgWmBasePing(void * data, struct xdg_wm_base * xdgWmBase, uint32_t serial)
|
||||
{
|
||||
xdg_wm_base_pong(xdgWmBase, serial);
|
||||
}
|
||||
|
||||
static const struct xdg_wm_base_listener xdgWmBaseListener = {
|
||||
.ping = xdgWmBasePing,
|
||||
};
|
||||
|
||||
// XDG Surface listeners.
|
||||
|
||||
static void xdgSurfaceConfigure(void * data, struct xdg_surface * xdgSurface,
|
||||
uint32_t serial)
|
||||
{
|
||||
if (state.configured)
|
||||
{
|
||||
state.resizeSerial = serial;
|
||||
waylandNeedsResize();
|
||||
}
|
||||
else
|
||||
{
|
||||
xdg_surface_ack_configure(xdgSurface, serial);
|
||||
state.configured = true;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct xdg_surface_listener xdgSurfaceListener = {
|
||||
.configure = xdgSurfaceConfigure,
|
||||
};
|
||||
|
||||
// XDG Toplevel listeners.
|
||||
|
||||
static void xdgToplevelConfigure(void * data, struct xdg_toplevel * xdgToplevel,
|
||||
int32_t width, int32_t height, struct wl_array * states)
|
||||
{
|
||||
state.width = width;
|
||||
state.height = height;
|
||||
state.fullscreen = false;
|
||||
state.floating = true;
|
||||
|
||||
enum xdg_toplevel_state * s;
|
||||
wl_array_for_each(s, states)
|
||||
{
|
||||
switch (*s)
|
||||
{
|
||||
case XDG_TOPLEVEL_STATE_FULLSCREEN:
|
||||
state.fullscreen = true;
|
||||
// fallthrough
|
||||
case XDG_TOPLEVEL_STATE_MAXIMIZED:
|
||||
case XDG_TOPLEVEL_STATE_TILED_LEFT:
|
||||
case XDG_TOPLEVEL_STATE_TILED_RIGHT:
|
||||
case XDG_TOPLEVEL_STATE_TILED_TOP:
|
||||
case XDG_TOPLEVEL_STATE_TILED_BOTTOM:
|
||||
state.floating = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void xdgToplevelClose(void * data, struct xdg_toplevel * xdgToplevel)
|
||||
{
|
||||
app_handleCloseEvent();
|
||||
}
|
||||
|
||||
static const struct xdg_toplevel_listener xdgToplevelListener = {
|
||||
.configure = xdgToplevelConfigure,
|
||||
.close = xdgToplevelClose,
|
||||
};
|
||||
|
||||
bool xdg_shellInit(struct wl_display * display, struct wl_surface * surface,
|
||||
const char * title, bool fullscreen, bool maximize, bool borderless,
|
||||
bool resizable)
|
||||
{
|
||||
if (!state.wmBase)
|
||||
{
|
||||
DEBUG_ERROR("Compositor missing xdg_wm_base, will not proceed");
|
||||
return false;
|
||||
}
|
||||
|
||||
xdg_wm_base_add_listener(state.wmBase, &xdgWmBaseListener, NULL);
|
||||
|
||||
state.surface = xdg_wm_base_get_xdg_surface(state.wmBase, surface);
|
||||
xdg_surface_add_listener(state.surface, &xdgSurfaceListener, NULL);
|
||||
|
||||
state.toplevel = xdg_surface_get_toplevel(state.surface);
|
||||
xdg_toplevel_add_listener(state.toplevel, &xdgToplevelListener, NULL);
|
||||
xdg_toplevel_set_title(state.toplevel, title);
|
||||
xdg_toplevel_set_app_id(state.toplevel, "looking-glass-client");
|
||||
|
||||
if (fullscreen)
|
||||
xdg_toplevel_set_fullscreen(state.toplevel, NULL);
|
||||
|
||||
if (maximize)
|
||||
xdg_toplevel_set_maximized(state.toplevel);
|
||||
|
||||
if (state.decorationManager)
|
||||
{
|
||||
state.toplevelDecoration = zxdg_decoration_manager_v1_get_toplevel_decoration(
|
||||
state.decorationManager, state.toplevel);
|
||||
if (state.toplevelDecoration)
|
||||
{
|
||||
zxdg_toplevel_decoration_v1_set_mode(state.toplevelDecoration,
|
||||
borderless ?
|
||||
ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE :
|
||||
ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void xdg_shellAckConfigureIfNeeded(void)
|
||||
{
|
||||
if (state.resizeSerial)
|
||||
{
|
||||
xdg_surface_ack_configure(state.surface, state.resizeSerial);
|
||||
state.resizeSerial = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void xdg_setFullscreen(bool fs)
|
||||
{
|
||||
if (fs)
|
||||
xdg_toplevel_set_fullscreen(state.toplevel, NULL);
|
||||
else
|
||||
xdg_toplevel_unset_fullscreen(state.toplevel);
|
||||
}
|
||||
|
||||
static bool xdg_getFullscreen(void)
|
||||
{
|
||||
return state.fullscreen;
|
||||
}
|
||||
|
||||
static void xdg_minimize(void)
|
||||
{
|
||||
xdg_toplevel_set_minimized(state.toplevel);
|
||||
}
|
||||
|
||||
static void xdg_shellResize(int w, int h)
|
||||
{
|
||||
if (!state.floating)
|
||||
return;
|
||||
|
||||
state.width = w;
|
||||
state.height = h;
|
||||
xdg_surface_set_window_geometry(state.surface, 0, 0, w, h);
|
||||
|
||||
waylandNeedsResize();
|
||||
}
|
||||
|
||||
static void xdg_setSize(int w, int h)
|
||||
{
|
||||
state.width = w;
|
||||
state.height = h;
|
||||
}
|
||||
|
||||
static void xdg_getSize(int * w, int * h)
|
||||
{
|
||||
*w = state.width;
|
||||
*h = state.height;
|
||||
}
|
||||
|
||||
static bool xdg_registryGlobalHandler(void * data,
|
||||
struct wl_registry * registry, uint32_t name, const char * interface,
|
||||
uint32_t version)
|
||||
{
|
||||
if (!strcmp(interface, xdg_wm_base_interface.name))
|
||||
{
|
||||
state.wmBase = wl_registry_bind(registry, name,
|
||||
&xdg_wm_base_interface, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!strcmp(interface, zxdg_decoration_manager_v1_interface.name))
|
||||
{
|
||||
state.decorationManager = wl_registry_bind(registry, name,
|
||||
&zxdg_decoration_manager_v1_interface, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void waylandDisplayCallback(uint32_t events, void * opaque)
|
||||
{
|
||||
struct wl_display * display = (struct wl_display *)opaque;
|
||||
if (events & EPOLLERR)
|
||||
wl_display_cancel_read(display);
|
||||
else
|
||||
wl_display_read_events(display);
|
||||
wl_display_dispatch_pending(display);
|
||||
}
|
||||
|
||||
static bool xdg_pollInit(struct wl_display * display)
|
||||
{
|
||||
state.displayFd = wl_display_get_fd(display);
|
||||
if (!waylandPollRegister(state.displayFd, waylandDisplayCallback,
|
||||
display, EPOLLIN))
|
||||
{
|
||||
DEBUG_ERROR("Failed register display to epoll: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void xdg_pollWait(struct wl_display * display, int epollFd,
|
||||
unsigned int time)
|
||||
{
|
||||
while (wl_display_prepare_read(display))
|
||||
wl_display_dispatch_pending(display);
|
||||
wl_display_flush(display);
|
||||
|
||||
struct epoll_event events[MAX_EPOLL_EVENTS];
|
||||
int count;
|
||||
if ((count = epoll_wait(epollFd, events, MAX_EPOLL_EVENTS, time)) < 0)
|
||||
{
|
||||
if (errno != EINTR)
|
||||
DEBUG_INFO("epoll failed: %s", strerror(errno));
|
||||
wl_display_cancel_read(display);
|
||||
return;
|
||||
}
|
||||
|
||||
bool sawDisplay = false;
|
||||
for (int i = 0; i < count; ++i) {
|
||||
struct WaylandPoll * poll = events[i].data.ptr;
|
||||
if (!poll->removed)
|
||||
poll->callback(events[i].events, poll->opaque);
|
||||
if (poll->fd == state.displayFd)
|
||||
sawDisplay = true;
|
||||
}
|
||||
|
||||
if (!sawDisplay)
|
||||
wl_display_cancel_read(display);
|
||||
}
|
||||
|
||||
WL_DesktopOps WLD_xdg =
|
||||
{
|
||||
.name = "xdg",
|
||||
.compositor = "",
|
||||
.shellInit = xdg_shellInit,
|
||||
.shellAckConfigureIfNeeded = xdg_shellAckConfigureIfNeeded,
|
||||
.setFullscreen = xdg_setFullscreen,
|
||||
.getFullscreen = xdg_getFullscreen,
|
||||
.minimize = xdg_minimize,
|
||||
.shellResize = xdg_shellResize,
|
||||
.setSize = xdg_setSize,
|
||||
.getSize = xdg_getSize,
|
||||
.registryGlobalHandler = xdg_registryGlobalHandler,
|
||||
.pollInit = xdg_pollInit,
|
||||
.pollWait = xdg_pollWait
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -89,18 +89,21 @@ void waylandEGLSwapBuffers(EGLDisplay display, EGLSurface surface, const struct
|
||||
if (wlWm.needsResize)
|
||||
{
|
||||
bool skipResize = false;
|
||||
wl_egl_window_resize(wlWm.eglWindow, wl_fixed_to_int(wlWm.width * wlWm.scale),
|
||||
wl_fixed_to_int(wlWm.height * wlWm.scale), 0, 0);
|
||||
|
||||
if (wlWm.width == 0 || wlWm.height == 0)
|
||||
int width, height;
|
||||
wlWm.desktop->getSize(&width, &height);
|
||||
wl_egl_window_resize(wlWm.eglWindow, wl_fixed_to_int(width * wlWm.scale),
|
||||
wl_fixed_to_int(height * wlWm.scale), 0, 0);
|
||||
|
||||
if (width == 0 || height == 0)
|
||||
skipResize = true;
|
||||
else if (wlWm.fractionalScale)
|
||||
{
|
||||
wl_surface_set_buffer_scale(wlWm.surface, 1);
|
||||
if (!wlWm.viewport)
|
||||
wlWm.viewport = wp_viewporter_get_viewport(wlWm.viewporter, wlWm.surface);
|
||||
wp_viewport_set_source(wlWm.viewport, 0, 0, wlWm.width * wlWm.scale, wlWm.height * wlWm.scale);
|
||||
wp_viewport_set_destination(wlWm.viewport, wlWm.width, wlWm.height);
|
||||
wp_viewport_set_source(wlWm.viewport, 0, 0, width * wlWm.scale, height * wlWm.scale);
|
||||
wp_viewport_set_destination(wlWm.viewport, width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -120,18 +123,18 @@ void waylandEGLSwapBuffers(EGLDisplay display, EGLSurface surface, const struct
|
||||
}
|
||||
|
||||
struct wl_region * region = wl_compositor_create_region(wlWm.compositor);
|
||||
wl_region_add(region, 0, 0, wlWm.width, wlWm.height);
|
||||
wl_region_add(region, 0, 0, width, height);
|
||||
wl_surface_set_opaque_region(wlWm.surface, region);
|
||||
wl_region_destroy(region);
|
||||
|
||||
app_handleResizeEvent(wlWm.width, wlWm.height, wl_fixed_to_double(wlWm.scale),
|
||||
app_handleResizeEvent(width, height, wl_fixed_to_double(wlWm.scale),
|
||||
(struct Border) {0, 0, 0, 0});
|
||||
app_invalidateWindow(true);
|
||||
waylandStopWaitFrame();
|
||||
wlWm.needsResize = skipResize;
|
||||
}
|
||||
|
||||
waylandShellAckConfigureIfNeeded();
|
||||
wlWm.desktop->shellAckConfigureIfNeeded();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -590,10 +590,13 @@ void waylandWarpPointer(int x, int y, bool exiting)
|
||||
return;
|
||||
}
|
||||
|
||||
int width, height;
|
||||
wlWm.desktop->getSize(&width, &height);
|
||||
|
||||
if (x < 0) x = 0;
|
||||
else if (x >= wlWm.width) x = wlWm.width - 1;
|
||||
else if (x >= width) x = width - 1;
|
||||
if (y < 0) y = 0;
|
||||
else if (y >= wlWm.height) y = wlWm.height - 1;
|
||||
else if (y >= height) y = height - 1;
|
||||
|
||||
struct wl_region * region = wl_compositor_create_region(wlWm.compositor);
|
||||
wl_region_add(region, x, y, 1, 1);
|
||||
|
||||
64
client/displayservers/Wayland/interface/desktop.h
Normal file
64
client/displayservers/Wayland/interface/desktop.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _H_WAYLAND_DESKTOP_H_
|
||||
#define _H_WAYLAND_DESKTOP_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <wayland-client.h>
|
||||
|
||||
typedef struct WL_DesktopOps
|
||||
{
|
||||
// the friendly name
|
||||
const char * name;
|
||||
|
||||
// the compositor process name to match
|
||||
const char * compositor;
|
||||
|
||||
bool (*shellInit)(
|
||||
struct wl_display * display, struct wl_surface * surface,
|
||||
const char * title, bool fullscreen, bool maximize,
|
||||
bool borderless, bool resizable);
|
||||
|
||||
void (*shellAckConfigureIfNeeded)(void);
|
||||
|
||||
void (*setFullscreen)(bool fs);
|
||||
|
||||
bool (*getFullscreen)(void);
|
||||
|
||||
void (*minimize)(void);
|
||||
|
||||
void (*shellResize)(int w, int h);
|
||||
|
||||
void (*setSize)(int w, int h);
|
||||
|
||||
void (*getSize)(int * w, int * h);
|
||||
|
||||
bool (*registryGlobalHandler)(
|
||||
void * data, struct wl_registry * registry,
|
||||
uint32_t name, const char * interface, uint32_t version);
|
||||
|
||||
bool (*pollInit)(struct wl_display * display);
|
||||
|
||||
void (*pollWait)(struct wl_display * display, int epollFd, unsigned int time);
|
||||
}
|
||||
WL_DesktopOps;
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -30,23 +30,6 @@
|
||||
#include "common/debug.h"
|
||||
#include "common/locking.h"
|
||||
|
||||
#ifdef ENABLE_LIBDECOR
|
||||
#include <libdecor.h>
|
||||
#endif
|
||||
|
||||
#define EPOLL_EVENTS 10 // Maximum number of fds we can process at once in waylandWait
|
||||
|
||||
#ifndef ENABLE_LIBDECOR
|
||||
static void waylandDisplayCallback(uint32_t events, void * opaque)
|
||||
{
|
||||
if (events & EPOLLERR)
|
||||
wl_display_cancel_read(wlWm.display);
|
||||
else
|
||||
wl_display_read_events(wlWm.display);
|
||||
wl_display_dispatch_pending(wlWm.display);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool waylandPollInit(void)
|
||||
{
|
||||
wlWm.epollFd = epoll_create1(EPOLL_CLOEXEC);
|
||||
@@ -61,58 +44,12 @@ bool waylandPollInit(void)
|
||||
LG_LOCK_INIT(wlWm.pollLock);
|
||||
LG_LOCK_INIT(wlWm.pollFreeLock);
|
||||
|
||||
#ifndef ENABLE_LIBDECOR
|
||||
wlWm.displayFd = wl_display_get_fd(wlWm.display);
|
||||
if (!waylandPollRegister(wlWm.displayFd, waylandDisplayCallback, NULL, EPOLLIN))
|
||||
{
|
||||
DEBUG_ERROR("Failed register display to epoll: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
return wlWm.desktop->pollInit(wlWm.display);
|
||||
}
|
||||
|
||||
void waylandWait(unsigned int time)
|
||||
{
|
||||
#ifdef ENABLE_LIBDECOR
|
||||
libdecor_dispatch(wlWm.libdecor, 0);
|
||||
#else
|
||||
while (wl_display_prepare_read(wlWm.display))
|
||||
wl_display_dispatch_pending(wlWm.display);
|
||||
wl_display_flush(wlWm.display);
|
||||
#endif
|
||||
|
||||
struct epoll_event events[EPOLL_EVENTS];
|
||||
int count;
|
||||
if ((count = epoll_wait(wlWm.epollFd, events, EPOLL_EVENTS, time)) < 0)
|
||||
{
|
||||
if (errno != EINTR)
|
||||
DEBUG_INFO("epoll failed: %s", strerror(errno));
|
||||
#ifndef ENABLE_LIBDECOR
|
||||
wl_display_cancel_read(wlWm.display);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef ENABLE_LIBDECOR
|
||||
bool sawDisplay = false;
|
||||
#endif
|
||||
for (int i = 0; i < count; ++i) {
|
||||
struct WaylandPoll * poll = events[i].data.ptr;
|
||||
if (!poll->removed)
|
||||
poll->callback(events[i].events, poll->opaque);
|
||||
#ifndef ENABLE_LIBDECOR
|
||||
if (poll->fd == wlWm.displayFd)
|
||||
sawDisplay = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef ENABLE_LIBDECOR
|
||||
if (!sawDisplay)
|
||||
wl_display_cancel_read(wlWm.display);
|
||||
#endif
|
||||
|
||||
wlWm.desktop->pollWait(wlWm.display, wlWm.epollFd, time);
|
||||
INTERLOCKED_SECTION(wlWm.pollFreeLock,
|
||||
{
|
||||
struct WaylandPoll * node;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
71
client/displayservers/Wayland/protocol/CMakeLists.txt
Normal file
71
client/displayservers/Wayland/protocol/CMakeLists.txt
Normal file
@@ -0,0 +1,71 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(wayland_protocol LANGUAGES C)
|
||||
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(WAYLAND REQUIRED IMPORTED_TARGET
|
||||
wayland-client
|
||||
wayland-cursor
|
||||
xkbcommon
|
||||
)
|
||||
|
||||
find_program(WAYLAND_SCANNER_EXECUTABLE NAMES wayland-scanner)
|
||||
|
||||
add_library(wayland_protocol STATIC
|
||||
)
|
||||
|
||||
macro(wayland_generate protocol_file output_file)
|
||||
add_custom_command(OUTPUT "${output_file}.h"
|
||||
COMMAND "${WAYLAND_SCANNER_EXECUTABLE}" client-header "${protocol_file}" "${output_file}.h"
|
||||
DEPENDS "${protocol_file}"
|
||||
VERBATIM)
|
||||
|
||||
add_custom_command(OUTPUT "${output_file}.c"
|
||||
COMMAND "${WAYLAND_SCANNER_EXECUTABLE}" private-code "${protocol_file}" "${output_file}.c"
|
||||
DEPENDS "${protocol_file}"
|
||||
VERBATIM)
|
||||
|
||||
target_sources(wayland_protocol PRIVATE "${output_file}.h" "${output_file}.c")
|
||||
endmacro()
|
||||
|
||||
set(WAYLAND_PROTOCOLS_BASE "${PROJECT_TOP}/repos/wayland-protocols")
|
||||
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/wayland")
|
||||
include_directories("${CMAKE_BINARY_DIR}/wayland")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/stable/xdg-shell/xdg-shell.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-xdg-shell-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/stable/presentation-time/presentation-time.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-presentation-time-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/stable/viewporter/viewporter.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-viewporter-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-xdg-decoration-unstable-v1-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/unstable/relative-pointer/relative-pointer-unstable-v1.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-relative-pointer-unstable-v1-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-pointer-constraints-unstable-v1-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-keyboard-shortcuts-inhibit-unstable-v1-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-idle-inhibit-unstable-v1-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/unstable/xdg-output/xdg-output-unstable-v1.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-xdg-output-unstable-v1-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/staging/xdg-activation/xdg-activation-v1.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-xdg-activation-v1-client-protocol")
|
||||
|
||||
target_link_libraries(wayland_protocol
|
||||
PkgConfig::WAYLAND
|
||||
)
|
||||
|
||||
target_include_directories(wayland_protocol
|
||||
PUBLIC
|
||||
"${CMAKE_BINARY_DIR}/wayland"
|
||||
)
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -40,13 +40,6 @@ static void registryGlobalHandler(void * data, struct wl_registry * registry,
|
||||
wlWm.compositor = wl_registry_bind(wlWm.registry, name,
|
||||
// we only need v3 to run, but v4 can use eglSwapBuffersWithDamageKHR
|
||||
&wl_compositor_interface, version > 4 ? 4 : version);
|
||||
#ifndef ENABLE_LIBDECOR
|
||||
else if (!strcmp(interface, xdg_wm_base_interface.name))
|
||||
wlWm.xdgWmBase = wl_registry_bind(wlWm.registry, name, &xdg_wm_base_interface, 1);
|
||||
else if (!strcmp(interface, zxdg_decoration_manager_v1_interface.name))
|
||||
wlWm.xdgDecorationManager = wl_registry_bind(wlWm.registry, name,
|
||||
&zxdg_decoration_manager_v1_interface, 1);
|
||||
#endif
|
||||
else if (!strcmp(interface, wp_presentation_interface.name))
|
||||
wlWm.presentation = wl_registry_bind(wlWm.registry, name,
|
||||
&wp_presentation_interface, 1);
|
||||
@@ -75,6 +68,9 @@ static void registryGlobalHandler(void * data, struct wl_registry * registry,
|
||||
else if (!strcmp(interface, xdg_activation_v1_interface.name))
|
||||
wlWm.xdgActivation = wl_registry_bind(wlWm.registry, name,
|
||||
&xdg_activation_v1_interface, 1);
|
||||
else if (wlWm.desktop->registryGlobalHandler(
|
||||
data, registry, name, interface, version))
|
||||
return;
|
||||
}
|
||||
|
||||
static void registryGlobalRemoveHandler(void * data,
|
||||
|
||||
@@ -1,178 +0,0 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "wayland.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <sys/epoll.h>
|
||||
|
||||
#include <libdecor.h>
|
||||
#include <wayland-client.h>
|
||||
|
||||
#include "app.h"
|
||||
#include "common/debug.h"
|
||||
|
||||
struct libdecor_configuration {
|
||||
uint32_t serial;
|
||||
|
||||
bool has_window_state;
|
||||
enum libdecor_window_state window_state;
|
||||
|
||||
bool has_size;
|
||||
int window_width;
|
||||
int window_height;
|
||||
};
|
||||
|
||||
static void libdecorHandleError(struct libdecor * context, enum libdecor_error error,
|
||||
const char *message)
|
||||
{
|
||||
DEBUG_ERROR("Got libdecor error (%d): %s", error, message);
|
||||
}
|
||||
|
||||
static void libdecorFrameConfigure(struct libdecor_frame * frame,
|
||||
struct libdecor_configuration * configuration, void * opaque)
|
||||
{
|
||||
if (!wlWm.configured)
|
||||
{
|
||||
xdg_surface_ack_configure(libdecor_frame_get_xdg_surface(frame), configuration->serial);
|
||||
wlWm.configured = true;
|
||||
return;
|
||||
}
|
||||
|
||||
int width, height;
|
||||
if (libdecor_configuration_get_content_size(configuration, frame, &width, &height))
|
||||
{
|
||||
wlWm.width = width;
|
||||
wlWm.height = height;
|
||||
|
||||
struct libdecor_state * state = libdecor_state_new(wlWm.width, wlWm.height);
|
||||
libdecor_frame_commit(wlWm.libdecorFrame, state, NULL);
|
||||
libdecor_state_free(state);
|
||||
}
|
||||
|
||||
enum libdecor_window_state windowState;
|
||||
if (libdecor_configuration_get_window_state(configuration, &windowState))
|
||||
wlWm.fullscreen = windowState & LIBDECOR_WINDOW_STATE_FULLSCREEN;
|
||||
|
||||
wlWm.needsResize = true;
|
||||
wlWm.resizeSerial = configuration->serial;
|
||||
app_invalidateWindow(true);
|
||||
waylandStopWaitFrame();
|
||||
}
|
||||
|
||||
static void libdecorFrameClose(struct libdecor_frame * frame, void * opaque)
|
||||
{
|
||||
app_handleCloseEvent();
|
||||
}
|
||||
|
||||
static void libdecorFrameCommit(struct libdecor_frame * frame, void * opaque)
|
||||
{
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
|
||||
static struct libdecor_interface libdecorListener = {
|
||||
libdecorHandleError,
|
||||
};
|
||||
|
||||
static struct libdecor_frame_interface libdecorFrameListener = {
|
||||
libdecorFrameConfigure,
|
||||
libdecorFrameClose,
|
||||
libdecorFrameCommit,
|
||||
};
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
static void libdecorCallback(uint32_t events, void * opaque)
|
||||
{
|
||||
libdecor_dispatch(wlWm.libdecor, 0);
|
||||
}
|
||||
|
||||
bool waylandShellInit(const char * title, bool fullscreen, bool maximize, bool borderless, bool resizable)
|
||||
{
|
||||
wlWm.libdecor = libdecor_new(wlWm.display, &libdecorListener);
|
||||
wlWm.libdecorFrame = libdecor_decorate(wlWm.libdecor, wlWm.surface, &libdecorFrameListener, NULL);
|
||||
|
||||
libdecor_frame_set_app_id(wlWm.libdecorFrame, "looking-glass-client");
|
||||
libdecor_frame_set_title(wlWm.libdecorFrame, title);
|
||||
libdecor_frame_map(wlWm.libdecorFrame);
|
||||
|
||||
if (resizable)
|
||||
libdecor_frame_set_capabilities(wlWm.libdecorFrame, LIBDECOR_ACTION_RESIZE);
|
||||
else
|
||||
libdecor_frame_unset_capabilities(wlWm.libdecorFrame, LIBDECOR_ACTION_RESIZE);
|
||||
|
||||
while (!wlWm.configured)
|
||||
libdecor_dispatch(wlWm.libdecor, 0);
|
||||
|
||||
if (!waylandPollRegister(libdecor_get_fd(wlWm.libdecor), libdecorCallback, NULL, EPOLLIN))
|
||||
{
|
||||
DEBUG_ERROR("Failed register display to epoll: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void waylandShellAckConfigureIfNeeded(void)
|
||||
{
|
||||
if (wlWm.resizeSerial)
|
||||
{
|
||||
xdg_surface_ack_configure(libdecor_frame_get_xdg_surface(wlWm.libdecorFrame), wlWm.resizeSerial);
|
||||
wlWm.resizeSerial = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void waylandSetFullscreen(bool fs)
|
||||
{
|
||||
if (fs)
|
||||
libdecor_frame_set_fullscreen(wlWm.libdecorFrame, NULL);
|
||||
else
|
||||
libdecor_frame_unset_fullscreen(wlWm.libdecorFrame);
|
||||
|
||||
libdecor_frame_set_visibility(wlWm.libdecorFrame, !fs);
|
||||
}
|
||||
|
||||
bool waylandGetFullscreen(void)
|
||||
{
|
||||
return wlWm.fullscreen;
|
||||
}
|
||||
|
||||
void waylandMinimize(void)
|
||||
{
|
||||
libdecor_frame_set_minimized(wlWm.libdecorFrame);
|
||||
}
|
||||
|
||||
void waylandShellResize(int w, int h)
|
||||
{
|
||||
if (!libdecor_frame_is_floating(wlWm.libdecorFrame))
|
||||
return;
|
||||
|
||||
wlWm.width = w;
|
||||
wlWm.height = h;
|
||||
|
||||
struct libdecor_state * state = libdecor_state_new(w, h);
|
||||
libdecor_frame_commit(wlWm.libdecorFrame, state, NULL);
|
||||
libdecor_state_free(state);
|
||||
|
||||
wlWm.needsResize = true;
|
||||
app_invalidateWindow(true);
|
||||
waylandStopWaitFrame();
|
||||
}
|
||||
@@ -1,184 +0,0 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "wayland.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <wayland-client.h>
|
||||
|
||||
#include "app.h"
|
||||
#include "common/debug.h"
|
||||
|
||||
// XDG WM base listeners.
|
||||
|
||||
static void xdgWmBasePing(void * data, struct xdg_wm_base * xdgWmBase, uint32_t serial)
|
||||
{
|
||||
xdg_wm_base_pong(xdgWmBase, serial);
|
||||
}
|
||||
|
||||
static const struct xdg_wm_base_listener xdgWmBaseListener = {
|
||||
.ping = xdgWmBasePing,
|
||||
};
|
||||
|
||||
// XDG Surface listeners.
|
||||
|
||||
static void xdgSurfaceConfigure(void * data, struct xdg_surface * xdgSurface,
|
||||
uint32_t serial)
|
||||
{
|
||||
if (wlWm.configured)
|
||||
{
|
||||
wlWm.needsResize = true;
|
||||
wlWm.resizeSerial = serial;
|
||||
app_invalidateWindow(true);
|
||||
waylandStopWaitFrame();
|
||||
}
|
||||
else
|
||||
{
|
||||
xdg_surface_ack_configure(xdgSurface, serial);
|
||||
wlWm.configured = true;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct xdg_surface_listener xdgSurfaceListener = {
|
||||
.configure = xdgSurfaceConfigure,
|
||||
};
|
||||
|
||||
// XDG Toplevel listeners.
|
||||
|
||||
static void xdgToplevelConfigure(void * data, struct xdg_toplevel * xdgToplevel,
|
||||
int32_t width, int32_t height, struct wl_array * states)
|
||||
{
|
||||
wlWm.width = width;
|
||||
wlWm.height = height;
|
||||
wlWm.fullscreen = false;
|
||||
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();
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -24,10 +24,13 @@
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <wayland-client.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/option.h"
|
||||
|
||||
#include "dynamic/wayland_desktops.h"
|
||||
|
||||
static struct Option waylandOptions[] =
|
||||
{
|
||||
{
|
||||
@@ -68,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[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
DEBUG_WARN("Compositor: UNKNOWN");
|
||||
DEBUG_INFO("Selected : %s", wlWm.desktop->name);
|
||||
|
||||
wl_list_init(&wlWm.surfaceOutputs);
|
||||
|
||||
wlWm.warpSupport = option_get_bool("wayland", "warpSupport");
|
||||
wlWm.useFractionalScale = option_get_bool("wayland", "fractionScale");
|
||||
|
||||
wlWm.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.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",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -37,11 +37,10 @@
|
||||
#include "common/countedbuffer.h"
|
||||
#include "common/ringbuffer.h"
|
||||
#include "interface/displayserver.h"
|
||||
#include "interface/desktop.h"
|
||||
|
||||
#include "wayland-xdg-shell-client-protocol.h"
|
||||
#include "wayland-presentation-time-client-protocol.h"
|
||||
#include "wayland-viewporter-client-protocol.h"
|
||||
#include "wayland-xdg-decoration-unstable-v1-client-protocol.h"
|
||||
#include "wayland-keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h"
|
||||
#include "wayland-pointer-constraints-unstable-v1-client-protocol.h"
|
||||
#include "wayland-relative-pointer-unstable-v1-client-protocol.h"
|
||||
@@ -100,6 +99,8 @@ struct WaylandDSState
|
||||
bool pointerInSurface;
|
||||
bool focusedOnSurface;
|
||||
|
||||
WL_DesktopOps * desktop;
|
||||
|
||||
struct wl_display * display;
|
||||
struct wl_surface * surface;
|
||||
struct wl_registry * registry;
|
||||
@@ -107,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,14 +300,6 @@ void waylandPresentationFree(void);
|
||||
bool waylandRegistryInit(void);
|
||||
void waylandRegistryFree(void);
|
||||
|
||||
// shell module
|
||||
bool waylandShellInit(const char * title, bool fullscreen, bool maximize, bool borderless, bool resizable);
|
||||
void waylandShellAckConfigureIfNeeded(void);
|
||||
void waylandSetFullscreen(bool fs);
|
||||
bool waylandGetFullscreen(void);
|
||||
void waylandMinimize(void);
|
||||
void waylandShellResize(int w, int h);
|
||||
|
||||
// window module
|
||||
bool waylandWindowInit(const char * title, bool fullscreen, bool maximize, bool borderless, bool resizable);
|
||||
void waylandWindowFree(void);
|
||||
@@ -331,3 +309,4 @@ bool waylandIsValidPointerPos(int x, int y);
|
||||
bool waylandWaitFrame(void);
|
||||
void waylandSkipFrame(void);
|
||||
void waylandStopWaitFrame(void);
|
||||
void waylandNeedsResize(void);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -112,7 +112,8 @@ bool waylandWindowInit(const char * title, bool fullscreen, bool maximize, bool
|
||||
|
||||
wl_surface_add_listener(wlWm.surface, &wlSurfaceListener, NULL);
|
||||
|
||||
if (!waylandShellInit(title, fullscreen, maximize, borderless, resizable))
|
||||
if (!wlWm.desktop->shellInit(wlWm.display, wlWm.surface,
|
||||
title, fullscreen, maximize, borderless, resizable))
|
||||
return false;
|
||||
|
||||
wl_surface_commit(wlWm.surface);
|
||||
@@ -127,12 +128,14 @@ void waylandWindowFree(void)
|
||||
|
||||
void waylandSetWindowSize(int x, int y)
|
||||
{
|
||||
waylandShellResize(x, y);
|
||||
wlWm.desktop->shellResize(x, y);
|
||||
}
|
||||
|
||||
bool waylandIsValidPointerPos(int x, int y)
|
||||
{
|
||||
return x >= 0 && x < wlWm.width && y >= 0 && y < wlWm.height;
|
||||
int width, height;
|
||||
wlWm.desktop->getSize(&width, &height);
|
||||
return x >= 0 && x < width && y >= 0 && y < height;
|
||||
}
|
||||
|
||||
static void frameHandler(void * opaque, struct wl_callback * callback, unsigned int data)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(displayserver_X11 LANGUAGES C)
|
||||
|
||||
find_package(PkgConfig)
|
||||
@@ -17,6 +17,10 @@ add_library(displayserver_X11 STATIC
|
||||
x11.c
|
||||
atoms.c
|
||||
clipboard.c
|
||||
cursor.c
|
||||
|
||||
wm/default.c
|
||||
wm/i3.c
|
||||
)
|
||||
|
||||
add_definitions(-D GLX_GLXEXT_PROTOTYPES)
|
||||
@@ -24,9 +28,10 @@ add_definitions(-D GLX_GLXEXT_PROTOTYPES)
|
||||
target_link_libraries(displayserver_X11
|
||||
PkgConfig::DISPLAYSERVER_X11
|
||||
lg_common
|
||||
lg_resources
|
||||
)
|
||||
|
||||
target_include_directories(displayserver_X11
|
||||
PRIVATE
|
||||
src
|
||||
.
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
105
client/displayservers/X11/cursor.c
Normal file
105
client/displayservers/X11/cursor.c
Normal file
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "cursor.h"
|
||||
#include "common/util.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
struct MemFile
|
||||
{
|
||||
const char * data;
|
||||
int size;
|
||||
int pos;
|
||||
};
|
||||
|
||||
static int x11cursor_read(XcursorFile *file, unsigned char * buf, int len)
|
||||
{
|
||||
struct MemFile * f = (struct MemFile *)file->closure;
|
||||
|
||||
if (f->pos == f->size)
|
||||
return 0;
|
||||
|
||||
len = min(f->size - f->pos, len);
|
||||
memcpy(buf, f->data + f->pos, len);
|
||||
f->pos += len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int x11cursor_write(XcursorFile *file, unsigned char * buf, int len)
|
||||
{
|
||||
errno = -EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int x11cursor_seek(XcursorFile *file, long offset, int whence)
|
||||
{
|
||||
struct MemFile * f = (struct MemFile *)file->closure;
|
||||
long target;
|
||||
|
||||
switch(whence)
|
||||
{
|
||||
case SEEK_SET:
|
||||
target = offset;
|
||||
break;
|
||||
|
||||
case SEEK_CUR:
|
||||
target = f->pos + offset;
|
||||
break;
|
||||
|
||||
case SEEK_END:
|
||||
target = f->size + offset;
|
||||
break;
|
||||
|
||||
default:
|
||||
errno = -EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (target < 0 || target > f->size)
|
||||
{
|
||||
errno = -EINVAL;
|
||||
return -1;
|
||||
}
|
||||
f->pos = target;
|
||||
return target;
|
||||
}
|
||||
|
||||
XcursorImages * x11cursor_load(const char * cursor, int size)
|
||||
{
|
||||
struct MemFile closure =
|
||||
{
|
||||
.data = cursor,
|
||||
.size = size,
|
||||
.pos = 0
|
||||
};
|
||||
|
||||
XcursorFile f =
|
||||
{
|
||||
.closure = &closure,
|
||||
.read = x11cursor_read,
|
||||
.write = x11cursor_write,
|
||||
.seek = x11cursor_seek
|
||||
};
|
||||
|
||||
return XcursorXcFileLoadAllImages(&f);
|
||||
}
|
||||
29
client/displayservers/X11/cursor.h
Normal file
29
client/displayservers/X11/cursor.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _H_X11DS_CURSOR_
|
||||
#define _H_X11DS_CURSOR_
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xcursor/Xcursor.h>
|
||||
|
||||
XcursorImages * x11cursor_load(const char * cursor, int size);
|
||||
|
||||
#endif
|
||||
39
client/displayservers/X11/wm.h
Normal file
39
client/displayservers/X11/wm.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _H_X11DS_WM_
|
||||
#define _H_X11DS_WM_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct X11WM
|
||||
{
|
||||
void (*setup)(void);
|
||||
bool (*init)(void);
|
||||
void (*deinit)(void);
|
||||
void (*setFullscreen)(bool enable);
|
||||
}
|
||||
X11WM;
|
||||
|
||||
extern X11WM X11WM_Default;
|
||||
extern X11WM X11WM_i3;
|
||||
|
||||
#endif
|
||||
71
client/displayservers/X11/wm/default.c
Normal file
71
client/displayservers/X11/wm/default.c
Normal file
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _H_X11DS_WM_DEFAULT_
|
||||
#define _H_X11DS_WM_DEFAULT_
|
||||
|
||||
#include "wm.h"
|
||||
#include "x11.h"
|
||||
#include "atoms.h"
|
||||
|
||||
static void wm_default_setup(void)
|
||||
{
|
||||
}
|
||||
|
||||
static bool wm_default_init(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static void wm_default_deinit(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void wm_default_setFullscreen(bool enable)
|
||||
{
|
||||
XEvent e =
|
||||
{
|
||||
.xclient = {
|
||||
.type = ClientMessage,
|
||||
.send_event = true,
|
||||
.message_type = x11atoms._NET_WM_STATE,
|
||||
.format = 32,
|
||||
.window = x11.window,
|
||||
.data.l = {
|
||||
enable ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE,
|
||||
x11atoms._NET_WM_STATE_FULLSCREEN,
|
||||
0
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
XSendEvent(x11.display, DefaultRootWindow(x11.display), False,
|
||||
SubstructureNotifyMask | SubstructureRedirectMask, &e);
|
||||
};
|
||||
|
||||
X11WM X11WM_Default =
|
||||
{
|
||||
.setup = wm_default_setup,
|
||||
.init = wm_default_init,
|
||||
.deinit = wm_default_deinit,
|
||||
.setFullscreen = wm_default_setFullscreen
|
||||
};
|
||||
|
||||
#endif
|
||||
194
client/displayservers/X11/wm/i3.c
Normal file
194
client/displayservers/X11/wm/i3.c
Normal file
@@ -0,0 +1,194 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _H_X11DS_WM_DEFAULT_
|
||||
#define _H_X11DS_WM_DEFAULT_
|
||||
|
||||
#include "wm.h"
|
||||
#include "x11.h"
|
||||
#include "atoms.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/option.h"
|
||||
#include "common/util.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
static struct Option options[] =
|
||||
{
|
||||
// app options
|
||||
{
|
||||
.module = "i3",
|
||||
.name = "globalFullScreen",
|
||||
.description = "Use i3's global full screen feature (spans all monitors)",
|
||||
.type = OPTION_TYPE_BOOL,
|
||||
.value.x_bool = false,
|
||||
},
|
||||
{0}
|
||||
};
|
||||
|
||||
struct i3state
|
||||
{
|
||||
int sock;
|
||||
bool globalFullScreen;
|
||||
};
|
||||
|
||||
static struct i3state i3;
|
||||
|
||||
static void wm_i3_setup(void)
|
||||
{
|
||||
option_register(options);
|
||||
}
|
||||
|
||||
static bool wm_i3_init(void)
|
||||
{
|
||||
memset(&i3, 0, sizeof(i3));
|
||||
|
||||
i3.globalFullScreen = option_get_bool("i3", "globalFullScreen");
|
||||
|
||||
FILE * fd = popen("i3 --get-socketpath", "r");
|
||||
if (!fd)
|
||||
return false;
|
||||
|
||||
struct sockaddr_un addr = { .sun_family = AF_UNIX };
|
||||
char path[sizeof(addr.sun_path)];
|
||||
int pathLen;
|
||||
if ((pathLen = fread(path, 1, sizeof(path), fd)) <= 0)
|
||||
{
|
||||
pclose(fd);
|
||||
return false;
|
||||
}
|
||||
pclose(fd);
|
||||
|
||||
if(path[pathLen-1] == '\n')
|
||||
--pathLen;
|
||||
path[pathLen] = '\0';
|
||||
|
||||
i3.sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (i3.sock < 0)
|
||||
{
|
||||
DEBUG_ERROR("Failed to create socket for i3 IPC");
|
||||
return false;
|
||||
}
|
||||
|
||||
strncpy(addr.sun_path, path, sizeof(addr.sun_path));
|
||||
if (connect(i3.sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
|
||||
{
|
||||
DEBUG_ERROR("Failed to connect to the i3 IPC socket");
|
||||
perror("connect");
|
||||
goto err_socket;
|
||||
}
|
||||
|
||||
DEBUG_INFO("i3 IPC Connected");
|
||||
return true;
|
||||
|
||||
err_socket:
|
||||
close(i3.sock);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void wm_i3_deinit(void)
|
||||
{
|
||||
close(i3.sock);
|
||||
}
|
||||
|
||||
static void wm_i3_setFullscreen(bool enable)
|
||||
{
|
||||
if (!i3.globalFullScreen)
|
||||
{
|
||||
X11WM_Default.setFullscreen(enable);
|
||||
return;
|
||||
}
|
||||
|
||||
struct i3Msg
|
||||
{
|
||||
char magic[6];
|
||||
uint32_t length;
|
||||
uint32_t type;
|
||||
char payload[0];
|
||||
}
|
||||
__attribute__((packed));
|
||||
|
||||
#define I3_IPC_TYPE_RUN_COMMAND 0
|
||||
|
||||
char cmd[128];
|
||||
int cmdLen = snprintf(cmd, sizeof(cmd),
|
||||
"[id=%lu] fullscreen toggle global",
|
||||
x11.window);
|
||||
|
||||
struct i3Msg *msg = alloca(sizeof(struct i3Msg) + cmdLen);
|
||||
memcpy(msg->magic, "i3-ipc", 6);
|
||||
msg->length = cmdLen;
|
||||
msg->type = I3_IPC_TYPE_RUN_COMMAND;
|
||||
memcpy(msg->payload, cmd, cmdLen);
|
||||
|
||||
int msgSize = sizeof(*msg) + msg->length;
|
||||
char * buf = (char *)msg;
|
||||
while(msgSize)
|
||||
{
|
||||
int wrote = write(i3.sock, buf, msgSize);
|
||||
if (wrote <= 0)
|
||||
{
|
||||
DEBUG_WARN("i3 IPC communication failure");
|
||||
return;
|
||||
}
|
||||
|
||||
buf += wrote;
|
||||
msgSize -= wrote;
|
||||
}
|
||||
|
||||
if ((msgSize = read(i3.sock, msg, sizeof(*msg))) < 0)
|
||||
{
|
||||
DEBUG_WARN("i3 IPC read failure");
|
||||
return;
|
||||
}
|
||||
|
||||
if (memcmp(msg->magic, "i3-ipc", 6) != 0 ||
|
||||
msg->type != I3_IPC_TYPE_RUN_COMMAND)
|
||||
{
|
||||
DEBUG_WARN("i3 IPC unexpected reply");
|
||||
return;
|
||||
}
|
||||
|
||||
// read and discard the payload
|
||||
while(msg->length)
|
||||
{
|
||||
int len = read(i3.sock, cmd, min(msg->length, sizeof(cmd)));
|
||||
if (len <= 0)
|
||||
{
|
||||
DEBUG_WARN("i3 IPC failed to read payload");
|
||||
return;
|
||||
}
|
||||
msg->length -= len;
|
||||
}
|
||||
};
|
||||
|
||||
X11WM X11WM_i3 =
|
||||
{
|
||||
.setup = wm_i3_setup,
|
||||
.init = wm_i3_init,
|
||||
.deinit = wm_i3_deinit,
|
||||
.setFullscreen = wm_i3_setFullscreen
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -23,7 +23,11 @@
|
||||
#include "x11.h"
|
||||
#include "atoms.h"
|
||||
#include "clipboard.h"
|
||||
#include "cursor.h"
|
||||
|
||||
#include "resources/icondata.h"
|
||||
#include "resources/no-input-cursor/16.xcur.h"
|
||||
#include "resources/no-input-cursor/32.xcur.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
@@ -53,10 +57,6 @@
|
||||
#include "common/event.h"
|
||||
#include "util.h"
|
||||
|
||||
#define _NET_WM_STATE_REMOVE 0
|
||||
#define _NET_WM_STATE_ADD 1
|
||||
#define _NET_WM_STATE_TOGGLE 2
|
||||
|
||||
struct X11DSState x11;
|
||||
|
||||
struct MwmHints
|
||||
@@ -166,6 +166,8 @@ static void x11DoPresent(uint64_t msc)
|
||||
|
||||
static void x11Setup(void)
|
||||
{
|
||||
X11WM_Default.setup();
|
||||
X11WM_i3 .setup();
|
||||
}
|
||||
|
||||
static bool x11Probe(void)
|
||||
@@ -230,6 +232,8 @@ static void x11CheckEWMHSupport(void)
|
||||
DEBUG_INFO("EWMH-complient window manager detected: %s", wmName);
|
||||
x11.ewmhSupport = true;
|
||||
|
||||
if (strcmp(wmName, "i3") == 0)
|
||||
x11.wm = &X11WM_i3;
|
||||
|
||||
XFree(wmName);
|
||||
out_supported:
|
||||
@@ -270,8 +274,9 @@ static bool x11Init(const LG_DSInitParams params)
|
||||
memset(&x11, 0, sizeof(x11));
|
||||
x11.xValuator = -1;
|
||||
x11.yValuator = -1;
|
||||
x11.display = XOpenDisplay(NULL);
|
||||
x11.display = XOpenDisplay(NULL);
|
||||
x11.jitRender = params.jitRender;
|
||||
x11.wm = &X11WM_Default;
|
||||
|
||||
XSetWindowAttributes swa =
|
||||
{
|
||||
@@ -369,6 +374,16 @@ static bool x11Init(const LG_DSInitParams params)
|
||||
// check for Extended Window Manager Hints support
|
||||
x11CheckEWMHSupport();
|
||||
|
||||
if (!x11.wm->init())
|
||||
{
|
||||
x11.wm = &X11WM_Default;
|
||||
if (!x11.wm->init())
|
||||
{
|
||||
DEBUG_ERROR("Failed to initialize the X11 window manager subsystem");
|
||||
goto fail_window;
|
||||
}
|
||||
}
|
||||
|
||||
if (x11atoms._NET_WM_PID)
|
||||
{
|
||||
pid_t pid = getpid();
|
||||
@@ -476,7 +491,7 @@ static bool x11Init(const LG_DSInitParams params)
|
||||
if (XIQueryVersion(x11.display, &major, &minor) != Success)
|
||||
{
|
||||
DEBUG_ERROR("Failed to query the XInput version");
|
||||
return false;
|
||||
goto fail_window;
|
||||
}
|
||||
|
||||
DEBUG_INFO("X11 XInput %d.%d in use", major, minor);
|
||||
@@ -615,29 +630,17 @@ static bool x11Init(const LG_DSInitParams params)
|
||||
XFreePixmap(x11.display, temp);
|
||||
}
|
||||
|
||||
/* create the square cursor */
|
||||
{
|
||||
static char data[] = { 0x07, 0x05, 0x07 };
|
||||
static char mask[] = { 0xff, 0xff, 0xff };
|
||||
XcursorImages * images;
|
||||
if (params.largeCursorDot)
|
||||
images = x11cursor_load(b_no_input_cursor_32_xcur,
|
||||
b_no_input_cursor_32_xcur_size);
|
||||
else
|
||||
images = x11cursor_load(b_no_input_cursor_16_xcur,
|
||||
b_no_input_cursor_16_xcur_size);
|
||||
|
||||
Colormap cmap = DefaultColormap(x11.display, DefaultScreen(x11.display));
|
||||
XColor colors[2] =
|
||||
{
|
||||
{ .pixel = BlackPixelOfScreen(DefaultScreenOfDisplay(x11.display)) },
|
||||
{ .pixel = WhitePixelOfScreen(DefaultScreenOfDisplay(x11.display)) }
|
||||
};
|
||||
|
||||
XQueryColors(x11.display, cmap, colors, 2);
|
||||
|
||||
Pixmap img = XCreateBitmapFromData(x11.display, x11.window, data, 3, 3);
|
||||
Pixmap msk = XCreateBitmapFromData(x11.display, x11.window, mask, 3, 3);
|
||||
|
||||
x11.cursors[LG_POINTER_SQUARE] = XCreatePixmapCursor(x11.display, img, msk,
|
||||
&colors[0], &colors[1], 1, 1);
|
||||
|
||||
XFreePixmap(x11.display, img);
|
||||
XFreePixmap(x11.display, msk);
|
||||
}
|
||||
x11.cursors[LG_POINTER_SQUARE] =
|
||||
XcursorImagesLoadCursor(x11.display, images);
|
||||
XcursorImagesDestroy(images);
|
||||
|
||||
/* initialize the rest of the cursors */
|
||||
const char * cursorLookup[LG_POINTER_COUNT] = {
|
||||
@@ -781,6 +784,7 @@ static void x11Free(void)
|
||||
if (x11.keysyms)
|
||||
XFree(x11.keysyms);
|
||||
|
||||
x11.wm->deinit();
|
||||
XCloseDisplay(x11.display);
|
||||
}
|
||||
|
||||
@@ -1964,24 +1968,7 @@ static void x11SetFullscreen(bool fs)
|
||||
if (x11.fullscreen == fs)
|
||||
return;
|
||||
|
||||
XEvent e =
|
||||
{
|
||||
.xclient = {
|
||||
.type = ClientMessage,
|
||||
.send_event = true,
|
||||
.message_type = x11atoms._NET_WM_STATE,
|
||||
.format = 32,
|
||||
.window = x11.window,
|
||||
.data.l = {
|
||||
fs ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE,
|
||||
x11atoms._NET_WM_STATE_FULLSCREEN,
|
||||
0
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
XSendEvent(x11.display, DefaultRootWindow(x11.display), False,
|
||||
SubstructureNotifyMask | SubstructureRedirectMask, &e);
|
||||
x11.wm->setFullscreen(fs);
|
||||
}
|
||||
|
||||
static bool x11GetFullscreen(void)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "interface/displayserver.h"
|
||||
#include "common/thread.h"
|
||||
#include "common/types.h"
|
||||
#include "wm.h"
|
||||
|
||||
enum Modifiers
|
||||
{
|
||||
@@ -48,11 +49,16 @@ enum Modifiers
|
||||
|
||||
#define MOD_COUNT (MOD_SUPER_RIGHT + 1)
|
||||
|
||||
#define _NET_WM_STATE_REMOVE 0
|
||||
#define _NET_WM_STATE_ADD 1
|
||||
#define _NET_WM_STATE_TOGGLE 2
|
||||
|
||||
struct X11DSState
|
||||
{
|
||||
Display * display;
|
||||
Window window;
|
||||
XVisualInfo * visual;
|
||||
X11WM * wm;
|
||||
|
||||
int minKeycode, maxKeycode;
|
||||
int symsPerKeycode;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -90,6 +90,7 @@ typedef struct LG_DSInitParams
|
||||
bool resizable;
|
||||
bool borderless;
|
||||
bool maximize;
|
||||
bool largeCursorDot;
|
||||
|
||||
// if true the renderer requires an OpenGL context
|
||||
bool opengl;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -72,8 +72,12 @@ LG_RendererRotate;
|
||||
typedef struct LG_RendererFormat
|
||||
{
|
||||
FrameType type; // frame type
|
||||
bool hdr; // if the frame is HDR or not
|
||||
bool hdrPQ; // if the HDR content is PQ mapped
|
||||
unsigned int screenWidth; // actual width of the host
|
||||
unsigned int screenHeight; // actual height of the host
|
||||
unsigned int dataWidth; // the width of the packed data
|
||||
unsigned int dataHeight; // the height of the packed data
|
||||
unsigned int frameWidth; // width of frame transmitted
|
||||
unsigned int frameHeight; // height of frame transmitted
|
||||
unsigned int stride; // scanline width (zero if compresed)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(renderers LANGUAGES C)
|
||||
|
||||
set(RENDERER_H "${CMAKE_BINARY_DIR}/include/dynamic/renderers.h")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(renderer_EGL LANGUAGES C CXX)
|
||||
|
||||
find_package(PkgConfig)
|
||||
@@ -56,6 +56,7 @@ build_shaders(
|
||||
shader/damage.vert
|
||||
shader/damage.frag
|
||||
shader/basic.vert
|
||||
shader/convert_24bit.frag
|
||||
shader/ffx_cas.frag
|
||||
shader/ffx_fsr1_easu.frag
|
||||
shader/ffx_fsr1_rcas.frag
|
||||
@@ -87,6 +88,7 @@ add_library(renderer_EGL STATIC
|
||||
postprocess.c
|
||||
ffx.c
|
||||
filter.c
|
||||
filter_24bit.c
|
||||
filter_ffx_cas.c
|
||||
filter_ffx_fsr1.c
|
||||
filter_downscale.c
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -100,7 +100,7 @@ static bool cursorTexInit(struct CursorTex * t,
|
||||
}
|
||||
|
||||
if (!egl_shaderCompile(t->shader,
|
||||
vertex_code, vertex_size, fragment_code, fragment_size, 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;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -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;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -50,6 +50,10 @@ struct DesktopShader
|
||||
GLint uScaleAlgo;
|
||||
GLint uNVGain;
|
||||
GLint uCBMode;
|
||||
GLint uIsHDR;
|
||||
GLint uMapHDRtoSDR;
|
||||
GLint uMapHDRGain;
|
||||
GLint uMapHDRPQ;
|
||||
};
|
||||
|
||||
struct EGL_Desktop
|
||||
@@ -64,6 +68,8 @@ struct EGL_Desktop
|
||||
|
||||
// internals
|
||||
int width, height;
|
||||
bool hdr;
|
||||
bool hdrPQ;
|
||||
LG_RendererRotate rotate;
|
||||
|
||||
bool useSpice;
|
||||
@@ -83,6 +89,11 @@ struct EGL_Desktop
|
||||
bool useDMA;
|
||||
LG_RendererFormat format;
|
||||
|
||||
// map HDR content to SDR
|
||||
bool mapHDRtoSDR;
|
||||
int peakLuminance;
|
||||
int maxCLL;
|
||||
|
||||
EGL_PostProcess * pp;
|
||||
_Atomic(bool) processFrame;
|
||||
};
|
||||
@@ -103,16 +114,20 @@ 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->uScaleAlgo = egl_shaderGetUniform(shader->shader, "scaleAlgo" );
|
||||
shader->uNVGain = egl_shaderGetUniform(shader->shader, "nvGain" );
|
||||
shader->uCBMode = egl_shaderGetUniform(shader->shader, "cbMode" );
|
||||
shader->uDesktopSize = egl_shaderGetUniform(shader->shader, "desktopSize" );
|
||||
shader->uTransform = egl_shaderGetUniform(shader->shader, "transform" );
|
||||
shader->uScaleAlgo = egl_shaderGetUniform(shader->shader, "scaleAlgo" );
|
||||
shader->uNVGain = egl_shaderGetUniform(shader->shader, "nvGain" );
|
||||
shader->uCBMode = egl_shaderGetUniform(shader->shader, "cbMode" );
|
||||
shader->uIsHDR = egl_shaderGetUniform(shader->shader, "isHDR" );
|
||||
shader->uMapHDRtoSDR = egl_shaderGetUniform(shader->shader, "mapHDRtoSDR" );
|
||||
shader->uMapHDRGain = egl_shaderGetUniform(shader->shader, "mapHDRGain" );
|
||||
shader->uMapHDRPQ = egl_shaderGetUniform(shader->shader, "mapHDRPQ" );
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -181,12 +196,19 @@ bool egl_desktopInit(EGL * egl, EGL_Desktop ** desktop_, EGLDisplay * display,
|
||||
desktop->scaleAlgo = option_get_int("egl", "scale" );
|
||||
desktop->useDMA = useDMA;
|
||||
|
||||
desktop->mapHDRtoSDR = option_get_bool("egl", "mapHDRtoSDR" );
|
||||
desktop->peakLuminance = option_get_int ("egl", "peakLuminance");
|
||||
desktop->maxCLL = option_get_int ("egl", "maxCLL" );
|
||||
|
||||
if (!egl_postProcessInit(&desktop->pp))
|
||||
{
|
||||
DEBUG_ERROR("Failed to initialize the post process manager");
|
||||
return false;
|
||||
}
|
||||
|
||||
// this MUST be first
|
||||
egl_postProcessAdd(desktop->pp, &egl_filter24bitOps);
|
||||
|
||||
egl_postProcessAdd(desktop->pp, &egl_filterDownscaleOps);
|
||||
egl_postProcessAdd(desktop->pp, &egl_filterFFXCASOps );
|
||||
egl_postProcessAdd(desktop->pp, &egl_filterFFXFSR1Ops );
|
||||
@@ -271,6 +293,28 @@ void egl_desktopConfigUI(EGL_Desktop * desktop)
|
||||
}
|
||||
igSliderInt("##nvgain", &desktop->nvGain, 0, desktop->nvMax, format, 0);
|
||||
igPopItemWidth();
|
||||
|
||||
bool mapHDRtoSDR = desktop->mapHDRtoSDR;
|
||||
int peakLuminance = desktop->peakLuminance;
|
||||
int maxCLL = desktop->maxCLL;
|
||||
|
||||
igSeparator();
|
||||
igCheckbox("Map HDR content to SDR", &mapHDRtoSDR);
|
||||
igSliderInt("Peak Luminance", &peakLuminance, 1, 10000,
|
||||
"%d nits",
|
||||
ImGuiInputTextFlags_CharsDecimal);
|
||||
igSliderInt("Max content light level", &maxCLL, 1, 10000,
|
||||
"%d nits", ImGuiInputTextFlags_CharsDecimal);
|
||||
|
||||
if (mapHDRtoSDR != desktop->mapHDRtoSDR ||
|
||||
peakLuminance != desktop->peakLuminance ||
|
||||
maxCLL != desktop->maxCLL)
|
||||
{
|
||||
desktop->mapHDRtoSDR = mapHDRtoSDR;
|
||||
desktop->peakLuminance = max(1, peakLuminance);
|
||||
desktop->maxCLL = max(1, maxCLL);
|
||||
app_invalidateWindow(true);
|
||||
}
|
||||
}
|
||||
|
||||
bool egl_desktopSetup(EGL_Desktop * desktop, const LG_RendererFormat format)
|
||||
@@ -296,6 +340,19 @@ bool egl_desktopSetup(EGL_Desktop * desktop, const LG_RendererFormat format)
|
||||
pixFmt = EGL_PF_RGBA16F;
|
||||
break;
|
||||
|
||||
case FRAME_TYPE_BGR_32:
|
||||
pixFmt = EGL_PF_BGR_32;
|
||||
break;
|
||||
|
||||
case FRAME_TYPE_RGB_24:
|
||||
pixFmt = EGL_PF_RGB_24;
|
||||
// the data width is correct per the format, but we are going to use a
|
||||
// 32-bit texture to load the data, so we need to alter the width for the
|
||||
// different bpp
|
||||
desktop->format.dataWidth =
|
||||
desktop->format.pitch / 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_ERROR("Unsupported frame format");
|
||||
return false;
|
||||
@@ -303,13 +360,16 @@ bool egl_desktopSetup(EGL_Desktop * desktop, const LG_RendererFormat format)
|
||||
|
||||
desktop->width = format.frameWidth;
|
||||
desktop->height = format.frameHeight;
|
||||
desktop->hdr = format.hdr;
|
||||
desktop->hdrPQ = format.hdrPQ;
|
||||
|
||||
if (!egl_textureSetup(
|
||||
desktop->texture,
|
||||
pixFmt,
|
||||
format.frameWidth,
|
||||
format.frameHeight,
|
||||
format.pitch
|
||||
desktop->format.dataWidth,
|
||||
desktop->format.dataHeight,
|
||||
desktop->format.stride,
|
||||
desktop->format.pitch
|
||||
))
|
||||
{
|
||||
DEBUG_ERROR("Failed to setup the desktop texture");
|
||||
@@ -454,6 +514,9 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth,
|
||||
desktop->useDMA && texture == desktop->texture ?
|
||||
&desktop->dmaShader : &desktop->shader;
|
||||
|
||||
const float mapHDRGain =
|
||||
desktop->maxCLL / desktop->peakLuminance;
|
||||
|
||||
EGL_Uniform uniforms[] =
|
||||
{
|
||||
{
|
||||
@@ -481,6 +544,26 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth,
|
||||
.type = EGL_UNIFORM_TYPE_1I,
|
||||
.location = shader->uCBMode,
|
||||
.f = { desktop->cbMode }
|
||||
},
|
||||
{
|
||||
.type = EGL_UNIFORM_TYPE_1I,
|
||||
.location = shader->uIsHDR,
|
||||
.i = { desktop->hdr }
|
||||
},
|
||||
{
|
||||
.type = EGL_UNIFORM_TYPE_1I,
|
||||
.location = shader->uMapHDRtoSDR,
|
||||
.i = { desktop->mapHDRtoSDR }
|
||||
},
|
||||
{
|
||||
.type = EGL_UNIFORM_TYPE_1F,
|
||||
.location = shader->uMapHDRGain,
|
||||
.f = { mapHDRGain }
|
||||
},
|
||||
{
|
||||
.type = EGL_UNIFORM_TYPE_1I,
|
||||
.location = shader->uMapHDRPQ,
|
||||
.f = { desktop->hdrPQ }
|
||||
}
|
||||
};
|
||||
|
||||
@@ -506,6 +589,7 @@ void egl_desktopSpiceConfigure(EGL_Desktop * desktop, int width, int height)
|
||||
EGL_PF_BGRA,
|
||||
width,
|
||||
height,
|
||||
width,
|
||||
width * 4
|
||||
))
|
||||
{
|
||||
@@ -529,7 +613,7 @@ void egl_desktopSpiceDrawFill(EGL_Desktop * desktop, int x, int y, int width,
|
||||
|
||||
for(; y < height; ++y)
|
||||
egl_textureUpdateRect(desktop->spiceTexture,
|
||||
x, y, width, 1, sizeof(line), (uint8_t *)line, false);
|
||||
x, y, width, 1, width, sizeof(line), (uint8_t *)line, false);
|
||||
|
||||
atomic_store(&desktop->processFrame, true);
|
||||
}
|
||||
@@ -538,7 +622,7 @@ void egl_desktopSpiceDrawBitmap(EGL_Desktop * desktop, int x, int y, int width,
|
||||
int height, int stride, uint8_t * data, bool topDown)
|
||||
{
|
||||
egl_textureUpdateRect(desktop->spiceTexture,
|
||||
x, y, width, height, stride, data, topDown);
|
||||
x, y, width, height, width, stride, data, topDown);
|
||||
atomic_store(&desktop->processFrame, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -202,6 +202,27 @@ static struct Option egl_options[] =
|
||||
.type = OPTION_TYPE_BOOL,
|
||||
.value.x_bool = true
|
||||
},
|
||||
{
|
||||
.module = "egl",
|
||||
.name = "mapHDRtoSDR",
|
||||
.description = "Map HDR content to the SDR color space",
|
||||
.type = OPTION_TYPE_BOOL,
|
||||
.value.x_bool = true
|
||||
},
|
||||
{
|
||||
.module = "egl",
|
||||
.name = "peakLuminance",
|
||||
.description = "The peak luminance level in nits for HDR to SDR mapping",
|
||||
.type = OPTION_TYPE_INT,
|
||||
.value.x_int = 250,
|
||||
},
|
||||
{
|
||||
.module = "egl",
|
||||
.name = "maxCLL",
|
||||
.description = "Maximum content light level in nits for HDR to SDR mapping",
|
||||
.type = OPTION_TYPE_INT,
|
||||
.value.x_int = 10000,
|
||||
},
|
||||
|
||||
{0}
|
||||
};
|
||||
@@ -748,7 +769,7 @@ static bool egl_renderStartup(LG_Renderer * renderer, bool useDMA)
|
||||
|
||||
EGLint attr[] =
|
||||
{
|
||||
EGL_BUFFER_SIZE , 24,
|
||||
EGL_BUFFER_SIZE , 30,
|
||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
||||
EGL_SAMPLE_BUFFERS , maxSamples > 0 ? 1 : 0,
|
||||
EGL_SAMPLES , maxSamples,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -37,7 +37,9 @@ typedef enum EGL_PixelFormat
|
||||
EGL_PF_RGBA,
|
||||
EGL_PF_BGRA,
|
||||
EGL_PF_RGBA10,
|
||||
EGL_PF_RGBA16F
|
||||
EGL_PF_RGBA16F,
|
||||
EGL_PF_BGR_32,
|
||||
EGL_PF_RGB_24
|
||||
}
|
||||
EGL_PixelFormat;
|
||||
|
||||
@@ -60,13 +62,17 @@ typedef struct EGL_TexSetup
|
||||
/* the height of the texture in pixels */
|
||||
size_t height;
|
||||
|
||||
/* the stide of the texture in bytes */
|
||||
/* the row length of the texture in pixels */
|
||||
size_t stride;
|
||||
|
||||
/* the row length of the texture in bytes */
|
||||
size_t pitch;
|
||||
}
|
||||
EGL_TexSetup;
|
||||
|
||||
typedef enum EGL_FilterType
|
||||
{
|
||||
EGL_FILTER_TYPE_INTERNAL,
|
||||
EGL_FILTER_TYPE_EFFECT,
|
||||
EGL_FILTER_TYPE_UPSCALE,
|
||||
EGL_FILTER_TYPE_DOWNSCALE
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -72,7 +72,8 @@ 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 */
|
||||
@@ -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,
|
||||
|
||||
220
client/renderers/EGL/filter_24bit.c
Normal file
220
client/renderers/EGL/filter_24bit.c
Normal file
@@ -0,0 +1,220 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "filter.h"
|
||||
#include "framebuffer.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/option.h"
|
||||
#include "cimgui.h"
|
||||
|
||||
#include "basic.vert.h"
|
||||
#include "convert_24bit.frag.h"
|
||||
|
||||
|
||||
typedef struct EGL_Filter24bit
|
||||
{
|
||||
EGL_Filter base;
|
||||
|
||||
bool enable;
|
||||
EGL_PixelFormat format;
|
||||
int useDMA;
|
||||
unsigned int width, height;
|
||||
unsigned int desktopWidth, desktopHeight;
|
||||
bool prepared;
|
||||
|
||||
EGL_Uniform uOutputSize;
|
||||
|
||||
EGL_Shader * shader;
|
||||
EGL_Framebuffer * fb;
|
||||
GLuint sampler[2];
|
||||
}
|
||||
EGL_Filter24bit;
|
||||
|
||||
static bool egl_filter24bitInit(EGL_Filter ** filter)
|
||||
{
|
||||
EGL_Filter24bit * this = calloc(1, sizeof(*this));
|
||||
if (!this)
|
||||
{
|
||||
DEBUG_ERROR("Failed to allocate ram");
|
||||
return false;
|
||||
}
|
||||
|
||||
this->useDMA = -1;
|
||||
|
||||
if (!egl_shaderInit(&this->shader))
|
||||
{
|
||||
DEBUG_ERROR("Failed to initialize the shader");
|
||||
goto error_this;
|
||||
}
|
||||
|
||||
if (!egl_framebufferInit(&this->fb))
|
||||
{
|
||||
DEBUG_ERROR("Failed to initialize the framebuffer");
|
||||
goto error_shader;
|
||||
}
|
||||
|
||||
glGenSamplers(ARRAY_LENGTH(this->sampler), this->sampler);
|
||||
glSamplerParameteri(this->sampler[0], GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glSamplerParameteri(this->sampler[0], GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glSamplerParameteri(this->sampler[0], GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(this->sampler[0], GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(this->sampler[1], GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glSamplerParameteri(this->sampler[1], GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glSamplerParameteri(this->sampler[1], GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(this->sampler[1], GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE);
|
||||
|
||||
*filter = &this->base;
|
||||
return true;
|
||||
|
||||
error_shader:
|
||||
egl_shaderFree(&this->shader);
|
||||
|
||||
error_this:
|
||||
free(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void egl_filter24bitFree(EGL_Filter * filter)
|
||||
{
|
||||
EGL_Filter24bit * this = UPCAST(EGL_Filter24bit, filter);
|
||||
|
||||
egl_shaderFree(&this->shader);
|
||||
egl_framebufferFree(&this->fb);
|
||||
glDeleteSamplers(ARRAY_LENGTH(this->sampler), this->sampler);
|
||||
free(this);
|
||||
}
|
||||
|
||||
static bool egl_filter24bitSetup(EGL_Filter * filter,
|
||||
enum EGL_PixelFormat pixFmt, unsigned int width, unsigned int height,
|
||||
unsigned int desktopWidth, unsigned int desktopHeight,
|
||||
bool useDMA)
|
||||
{
|
||||
EGL_Filter24bit * this = UPCAST(EGL_Filter24bit, filter);
|
||||
|
||||
if (pixFmt != EGL_PF_BGR_32 && pixFmt != EGL_PF_RGB_24)
|
||||
return false;
|
||||
|
||||
if (this->useDMA != useDMA || this->format != pixFmt)
|
||||
{
|
||||
EGL_ShaderDefine defines[] =
|
||||
{
|
||||
{"OUTPUT", pixFmt == EGL_PF_BGR_32 ? "fragColor.bgra" : "fragColor.rgba" },
|
||||
{0}
|
||||
};
|
||||
|
||||
if (!egl_shaderCompile(this->shader,
|
||||
b_shader_basic_vert , b_shader_basic_vert_size,
|
||||
b_shader_convert_24bit_frag, b_shader_convert_24bit_frag_size,
|
||||
useDMA, defines)
|
||||
)
|
||||
{
|
||||
DEBUG_ERROR("Failed to compile the shader");
|
||||
return false;
|
||||
}
|
||||
|
||||
this->uOutputSize.type = EGL_UNIFORM_TYPE_2F;
|
||||
this->uOutputSize.location =
|
||||
egl_shaderGetUniform(this->shader, "outputSize");
|
||||
|
||||
this->useDMA = useDMA;
|
||||
this->prepared = false;
|
||||
}
|
||||
|
||||
if (this->prepared &&
|
||||
this->width == width &&
|
||||
this->height == height &&
|
||||
this->desktopWidth == desktopWidth &&
|
||||
this->desktopHeight == desktopHeight)
|
||||
return true;
|
||||
|
||||
if (!egl_framebufferSetup(this->fb, pixFmt, desktopWidth, desktopHeight))
|
||||
return false;
|
||||
|
||||
this->format = pixFmt;
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
this->desktopWidth = desktopWidth;
|
||||
this->desktopHeight = desktopHeight;
|
||||
this->prepared = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void egl_filter24bitGetOutputRes(EGL_Filter * filter,
|
||||
unsigned int *width, unsigned int *height)
|
||||
{
|
||||
EGL_Filter24bit * this = UPCAST(EGL_Filter24bit, filter);
|
||||
*width = this->desktopWidth;
|
||||
*height = this->desktopHeight;
|
||||
}
|
||||
|
||||
static bool egl_filter24bitPrepare(EGL_Filter * filter)
|
||||
{
|
||||
EGL_Filter24bit * this = UPCAST(EGL_Filter24bit, filter);
|
||||
|
||||
if (this->prepared)
|
||||
return true;
|
||||
|
||||
this->uOutputSize.f[0] = this->desktopWidth;
|
||||
this->uOutputSize.f[1] = this->desktopHeight;
|
||||
egl_shaderSetUniforms(this->shader, &this->uOutputSize, 1);
|
||||
|
||||
this->prepared = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static EGL_Texture * egl_filter24bitRun(EGL_Filter * filter,
|
||||
EGL_FilterRects * rects, EGL_Texture * texture)
|
||||
{
|
||||
EGL_Filter24bit * this = UPCAST(EGL_Filter24bit, filter);
|
||||
|
||||
egl_framebufferBind(this->fb);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
egl_textureBind(texture);
|
||||
|
||||
glBindSampler(0, this->sampler[0]);
|
||||
|
||||
egl_shaderUse(this->shader);
|
||||
egl_filterRectsRender(this->shader, rects);
|
||||
|
||||
return egl_framebufferGetTexture(this->fb);
|
||||
}
|
||||
|
||||
EGL_FilterOps egl_filter24bitOps =
|
||||
{
|
||||
.id = "24bit",
|
||||
.name = "24bit",
|
||||
.type = EGL_FILTER_TYPE_INTERNAL,
|
||||
.earlyInit = NULL,
|
||||
.init = egl_filter24bitInit,
|
||||
.free = egl_filter24bitFree,
|
||||
.imguiConfig = NULL,
|
||||
.saveState = NULL,
|
||||
.loadState = NULL,
|
||||
.setup = egl_filter24bitSetup,
|
||||
.getOutputRes = egl_filter24bitGetOutputRes,
|
||||
.prepare = egl_filter24bitPrepare,
|
||||
.run = egl_filter24bitRun
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -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");
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -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");
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -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");
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
extern EGL_FilterOps egl_filter24bitOps;
|
||||
extern EGL_FilterOps egl_filterDownscaleOps;
|
||||
extern EGL_FilterOps egl_filterFFXCASOps;
|
||||
extern EGL_FilterOps egl_filterFFXFSR1Ops;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -64,7 +64,7 @@ void egl_framebufferFree(EGL_Framebuffer ** fb)
|
||||
bool egl_framebufferSetup(EGL_Framebuffer * this, enum EGL_PixelFormat pixFmt,
|
||||
unsigned int width, unsigned int height)
|
||||
{
|
||||
if (!egl_textureSetup(this->tex, pixFmt, width, height, 0))
|
||||
if (!egl_textureSetup(this->tex, pixFmt, width, height, 0, 0))
|
||||
{
|
||||
DEBUG_ERROR("Failed to setup the texture");
|
||||
return false;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -48,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;
|
||||
}
|
||||
|
||||
@@ -638,25 +664,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, tex->format.pixFmt, sizeX, sizeY,
|
||||
desktopWidth, desktopHeight, useDMA) ||
|
||||
!egl_filterPrepare(filter))
|
||||
continue;
|
||||
|
||||
if (lastFilter)
|
||||
egl_filterRelease(lastFilter);
|
||||
texture = egl_filterRun(filter, &filterRects, texture);
|
||||
egl_filterGetOutputRes(filter, &sizeX, &sizeY);
|
||||
|
||||
lastFilter = filter;
|
||||
if (lastFilter)
|
||||
egl_filterRelease(lastFilter);
|
||||
|
||||
// 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;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -65,7 +65,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 +90,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,8 +211,12 @@ 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";
|
||||
@@ -225,12 +230,13 @@ bool egl_shaderCompile(EGL_Shader * this, const char * vertex_code,
|
||||
src += strlen(search);
|
||||
}
|
||||
|
||||
const int diff = (strlen(replace) - strlen(search)) * instances;
|
||||
char * newCode = malloc(fragment_size + diff);
|
||||
const int diff = (strlen(replace) - strlen(search)) * instances;
|
||||
const int newLen = fragment_size + diff;
|
||||
newCode = malloc(newLen + 1);
|
||||
if (!newCode)
|
||||
{
|
||||
DEBUG_ERROR("Out of memory");
|
||||
return false;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
src = fragment_code;
|
||||
@@ -250,20 +256,94 @@ bool egl_shaderCompile(EGL_Shader * this, const char * vertex_code,
|
||||
|
||||
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 - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int processedLen = fragment_size;
|
||||
const char * defineFormat = "#define %s %s\n";
|
||||
for(const EGL_ShaderDefine * define = defines; define->name; ++define)
|
||||
processedLen += snprintf(NULL, 0, defineFormat, define->name, define->value);
|
||||
|
||||
processed = malloc(processedLen);
|
||||
if (!processed)
|
||||
{
|
||||
DEBUG_ERROR("Out of memory");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
memcpy(processed, fragment_code, insertPos);
|
||||
|
||||
int offset = insertPos;
|
||||
for(const EGL_ShaderDefine * define = defines; define->name; ++define)
|
||||
offset += sprintf(processed + offset, defineFormat,
|
||||
define->name, define->value);
|
||||
|
||||
memcpy(
|
||||
processed + offset,
|
||||
fragment_code + insertPos,
|
||||
fragment_size - insertPos);
|
||||
|
||||
fragment_code = processed;
|
||||
fragment_size = processedLen;
|
||||
}
|
||||
|
||||
result = shaderCompile(this,
|
||||
vertex_code , vertex_size,
|
||||
fragment_code, fragment_size);
|
||||
|
||||
exit:
|
||||
free(processed);
|
||||
free(newCode);
|
||||
return result;
|
||||
}
|
||||
|
||||
void egl_shaderSetUniforms(EGL_Shader * this, EGL_Uniform * uniforms, int count)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -93,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);
|
||||
|
||||
32
client/renderers/EGL/shader/convert_24bit.frag
Normal file
32
client/renderers/EGL/shader/convert_24bit.frag
Normal 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
|
||||
);
|
||||
}
|
||||
@@ -9,6 +9,7 @@ precision highp float;
|
||||
#define EGL_SCALE_MAX 3
|
||||
|
||||
#include "color_blind.h"
|
||||
#include "hdr.h"
|
||||
|
||||
in vec2 uv;
|
||||
out vec4 color;
|
||||
@@ -19,6 +20,10 @@ uniform int scaleAlgo;
|
||||
|
||||
uniform float nvGain;
|
||||
uniform int cbMode;
|
||||
uniform bool isHDR;
|
||||
uniform bool mapHDRtoSDR;
|
||||
uniform float mapHDRGain;
|
||||
uniform bool mapHDRPQ;
|
||||
|
||||
void main()
|
||||
{
|
||||
@@ -38,6 +43,9 @@ void main()
|
||||
}
|
||||
}
|
||||
|
||||
if (isHDR && mapHDRtoSDR)
|
||||
color.rgb = mapToSDR(color.rgb, mapHDRGain, mapHDRPQ);
|
||||
|
||||
if (cbMode > 0)
|
||||
color = cbTransform(color, cbMode);
|
||||
|
||||
|
||||
108
client/renderers/EGL/shader/hdr.h
Normal file
108
client/renderers/EGL/shader/hdr.h
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
_______ _____ __ __ ____ __
|
||||
/ ____(_)___ ___ ____ ___ ____ _ / ___// /_ ____ _____/ /__ _____ / __ \____ ______/ /__
|
||||
/ / / / __ \/ _ \/ __ `__ \/ __ `/ \__ \/ __ \/ __ `/ __ / _ \/ ___/ / /_/ / __ `/ ___/ //_/
|
||||
/ /___/ / / / / __/ / / / / / /_/ / ___/ / / / / /_/ / /_/ / __/ / / ____/ /_/ / /__/ ,<
|
||||
\____/_/_/ /_/\___/_/ /_/ /_/\__,_/ /____/_/ /_/\__,_/\__,_/\___/_/ /_/ \__,_/\___/_/|_|
|
||||
http://en.sbence.hu/ Shader: Try to get the SDR part of HDR content
|
||||
*/
|
||||
|
||||
/**
|
||||
* Translated to GLSL, original source is:
|
||||
* https://github.com/VoidXH/Cinema-Shader-Pack
|
||||
*/
|
||||
|
||||
// Configuration ---------------------------------------------------------------
|
||||
const float knee = 0.75; // Compressor knee position
|
||||
const float ratio = 4.0; // Compressor ratio: 1 = disabled, <1 = expander
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Precalculated values
|
||||
const float compressor = 1.0 / ratio;
|
||||
|
||||
// PQ constants
|
||||
const float m1inv = 16384.0 / 2610.0;
|
||||
const float m2inv = 32.0 / 2523.0;
|
||||
const float c1 = 3424.0 / 4096.0;
|
||||
const float c2 = 2413.0 / 128.0;
|
||||
const float c3 = 2392.0 / 128.0;
|
||||
|
||||
float minGain(vec3 pixel) { return min(pixel.r, min(pixel.g, pixel.b)); }
|
||||
float maxGain(vec3 pixel) { return max(pixel.r, max(pixel.g, pixel.b)); }
|
||||
float midGain(vec3 pixel)
|
||||
{
|
||||
return pixel.r < pixel.g ?
|
||||
(pixel.r < pixel.b ?
|
||||
min(pixel.g, pixel.b) : // min = r
|
||||
min(pixel.r, pixel.g)) : // min = b
|
||||
(pixel.g < pixel.b ?
|
||||
min(pixel.r, pixel.b) : // min = g
|
||||
min(pixel.r, pixel.g)); // min = b
|
||||
}
|
||||
|
||||
vec3 compress(vec3 pixel)
|
||||
{
|
||||
float maxGain = maxGain(pixel);
|
||||
return pixel * (maxGain < knee ? maxGain :
|
||||
knee + max(maxGain - knee, 0.0) * compressor) / maxGain;
|
||||
}
|
||||
|
||||
vec3 fixClip(vec3 pixel)
|
||||
{
|
||||
// keep the (mid - min) / (max - min) ratio
|
||||
float preMin = minGain(pixel);
|
||||
float preMid = midGain(pixel);
|
||||
float preMax = maxGain(pixel);
|
||||
vec3 clip = clamp(pixel, 0.0, 1.0);
|
||||
float postMin = minGain(clip);
|
||||
float postMid = midGain(clip);
|
||||
float postMax = maxGain(clip);
|
||||
float ratio = (preMid - preMin) / (preMax - preMin);
|
||||
float newMid = ratio * (postMax - postMin) + postMin;
|
||||
return vec3(clip.r != postMid ? clip.r : newMid,
|
||||
clip.g != postMid ? clip.g : newMid,
|
||||
clip.b != postMid ? clip.b : newMid);
|
||||
}
|
||||
|
||||
// Returns luminance in nits
|
||||
vec3 pq2lin(vec3 pq, float gain)
|
||||
{
|
||||
vec3 p = pow(pq, vec3(m2inv));
|
||||
vec3 d = max(p - c1, vec3(0.0)) / (c2 - c3 * p);
|
||||
return pow(d, vec3(m1inv)) * gain;
|
||||
}
|
||||
|
||||
vec3 srgb2lin(vec3 c)
|
||||
{
|
||||
vec3 v = c / 12.92;
|
||||
vec3 v2 = pow((c + vec3(0.055)) / 1.055, vec3(2.4));
|
||||
vec3 threshold = vec3(0.04045);
|
||||
vec3 result = mix(v, v2, greaterThanEqual(c, threshold));
|
||||
return result;
|
||||
}
|
||||
|
||||
vec3 lin2srgb(vec3 c)
|
||||
{
|
||||
vec3 v = c * 12.92;
|
||||
vec3 v2 = pow(c, vec3(1.0/2.4)) * 1.055 - 0.055;
|
||||
vec3 threshold = vec3(0.0031308);
|
||||
vec3 result = mix(v, v2, greaterThanEqual(c, threshold));
|
||||
return result;
|
||||
}
|
||||
|
||||
// in linear space
|
||||
vec3 bt2020to709(vec3 bt2020)
|
||||
{
|
||||
return vec3(
|
||||
bt2020.r * 1.6605 + bt2020.g * -0.5876 + bt2020.b * -0.0728,
|
||||
bt2020.r * -0.1246 + bt2020.g * 1.1329 + bt2020.b * -0.0083,
|
||||
bt2020.r * -0.0182 + bt2020.g * -0.1006 + bt2020.b * 1.1187);
|
||||
}
|
||||
|
||||
vec3 mapToSDR(vec3 color, float gain, bool pq)
|
||||
{
|
||||
if (pq)
|
||||
color = pq2lin(color.rgb, gain);
|
||||
color = bt2020to709(color);
|
||||
return lin2srgb(compress(color));
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -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
|
||||
@@ -113,13 +113,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,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -112,7 +112,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,
|
||||
@@ -187,7 +187,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 +195,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->pitch);
|
||||
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;
|
||||
dst += texture->format.pitch;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,7 +241,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.width);
|
||||
glTexSubImage2D(GL_TEXTURE_2D,
|
||||
0, 0, 0,
|
||||
texture->format.width,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -162,12 +162,12 @@ static bool egl_texDMABUFUpdate(EGL_Texture * texture,
|
||||
const uint64_t modifier = DRM_FORMAT_MOD_LINEAR;
|
||||
EGLAttrib attribs[] =
|
||||
{
|
||||
EGL_WIDTH , texture->format.width,
|
||||
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_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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -92,29 +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,
|
||||
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;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -30,8 +30,19 @@
|
||||
|
||||
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)
|
||||
{
|
||||
//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:
|
||||
// fallthrough
|
||||
|
||||
case EGL_PF_BGRA:
|
||||
fmt->bpp = 4;
|
||||
fmt->format = GL_BGRA_EXT;
|
||||
@@ -53,7 +64,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_BGRA1010102;
|
||||
fmt->fourcc = DRM_FORMAT_ABGR2101010;
|
||||
break;
|
||||
|
||||
case EGL_PF_RGBA16F:
|
||||
@@ -64,27 +75,26 @@ bool egl_texUtilGetFormat(const EGL_TexSetup * setup, EGL_TexFormat * fmt)
|
||||
fmt->fourcc = DRM_FORMAT_ABGR16161616F;
|
||||
break;
|
||||
|
||||
case EGL_PF_RGB_24:
|
||||
fmt->bpp = 3;
|
||||
fmt->format = GL_BGRA_EXT;
|
||||
fmt->intFormat = GL_BGRA_EXT;
|
||||
fmt->dataType = GL_UNSIGNED_BYTE;
|
||||
fmt->fourcc = DRM_FORMAT_ARGB8888;
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_ERROR("Unsupported pixel format");
|
||||
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 +105,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 |
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user