From e5e3307697eeae4ac63989955440ab7792ba45f0 Mon Sep 17 00:00:00 2001 From: neatnoise Date: Thu, 19 Feb 2026 17:03:19 +0100 Subject: [PATCH 01/29] Add Vulkan video encoder for Linux --- .github/workflows/ci-freebsd.yml | 2 + cmake/compile_definitions/linux.cmake | 15 + cmake/prep/options.cmake | 2 + docs/configuration.md | 5 + packaging/linux/Arch/PKGBUILD | 1 + packaging/linux/copr/Sunshine.spec | 4 + packaging/sunshine.rb | 2 + scripts/linux_build.sh | 5 + src/config.cpp | 6 + src/config.h | 4 + src/platform/common.h | 1 + src/platform/linux/kmsgrab.cpp | 15 +- src/platform/linux/portalgrab.cpp | 10 +- src/platform/linux/vulkan_encode.cpp | 266 ++++++++++++++++++ src/platform/linux/vulkan_encode.h | 36 +++ src/video.cpp | 117 +++++++- src_assets/common/assets/web/config.html | 13 +- .../assets/web/configs/tabs/Advanced.vue | 2 + .../web/configs/tabs/ContainerEncoders.vue | 8 + .../configs/tabs/encoders/VulkanEncoder.vue | 42 +++ .../assets/web/public/assets/locale/en.json | 4 + 21 files changed, 555 insertions(+), 5 deletions(-) create mode 100644 src/platform/linux/vulkan_encode.cpp create mode 100644 src/platform/linux/vulkan_encode.h create mode 100644 src_assets/common/assets/web/configs/tabs/encoders/VulkanEncoder.vue diff --git a/.github/workflows/ci-freebsd.yml b/.github/workflows/ci-freebsd.yml index 2b6a42286c8..4ea604883d0 100644 --- a/.github/workflows/ci-freebsd.yml +++ b/.github/workflows/ci-freebsd.yml @@ -113,6 +113,8 @@ jobs: devel/pkgconf \ ftp/curl \ graphics/libdrm \ + graphics/vulkan-headers \ + graphics/vulkan-loader \ graphics/wayland \ lang/python314 \ multimedia/libva \ diff --git a/cmake/compile_definitions/linux.cmake b/cmake/compile_definitions/linux.cmake index 89769acf3e1..7eddefbd26d 100644 --- a/cmake/compile_definitions/linux.cmake +++ b/cmake/compile_definitions/linux.cmake @@ -120,6 +120,21 @@ if(LIBVA_FOUND) "${CMAKE_SOURCE_DIR}/src/platform/linux/vaapi.cpp") endif() +# vulkan video encoding (via FFmpeg) +if(${SUNSHINE_ENABLE_VULKAN}) + find_package(Vulkan REQUIRED) +else() + set(Vulkan_FOUND OFF) +endif() +if(Vulkan_FOUND) + list(APPEND SUNSHINE_DEFINITIONS SUNSHINE_BUILD_VULKAN=1) + include_directories(SYSTEM ${Vulkan_INCLUDE_DIRS}) + list(APPEND PLATFORM_LIBRARIES ${Vulkan_LIBRARIES}) + list(APPEND PLATFORM_TARGET_FILES + "${CMAKE_SOURCE_DIR}/src/platform/linux/vulkan_encode.h" + "${CMAKE_SOURCE_DIR}/src/platform/linux/vulkan_encode.cpp") +endif() + # wayland if(${SUNSHINE_ENABLE_WAYLAND}) find_package(Wayland REQUIRED) diff --git a/cmake/prep/options.cmake b/cmake/prep/options.cmake index 67d9a568a43..6ce5b1ab0e0 100644 --- a/cmake/prep/options.cmake +++ b/cmake/prep/options.cmake @@ -58,6 +58,8 @@ elseif(UNIX) # Linux "Enable KMS grab if available." ON) option(SUNSHINE_ENABLE_VAAPI "Enable building vaapi specific code." ON) + option(SUNSHINE_ENABLE_VULKAN + "Enable Vulkan video encoding." ON) option(SUNSHINE_ENABLE_WAYLAND "Enable building wayland specific code." ON) option(SUNSHINE_ENABLE_X11 diff --git a/docs/configuration.md b/docs/configuration.md index 97f08576cd1..12e5c242dea 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -2155,6 +2155,11 @@ editing the `conf` file in a text editor. Use the examples as reference. vaapi Use VA-API (AMD, Intel) + + vulkan + Use Vulkan encoder (AMD, Intel, NVIDIA). + @note{Applies to Linux only.} + software Encoding occurs on the CPU diff --git a/packaging/linux/Arch/PKGBUILD b/packaging/linux/Arch/PKGBUILD index 4ed601620e1..0ecc1d781a2 100644 --- a/packaging/linux/Arch/PKGBUILD +++ b/packaging/linux/Arch/PKGBUILD @@ -50,6 +50,7 @@ depends=( 'openssl' 'opus' 'udev' + 'vulkan-icd-loader' 'which' ) diff --git a/packaging/linux/copr/Sunshine.spec b/packaging/linux/copr/Sunshine.spec index 5b42be37f28..055e8279b61 100644 --- a/packaging/linux/copr/Sunshine.spec +++ b/packaging/linux/copr/Sunshine.spec @@ -44,6 +44,8 @@ BuildRequires: openssl-devel BuildRequires: pipewire-devel BuildRequires: rpm-build BuildRequires: systemd-rpm-macros +BuildRequires: vulkan-headers +BuildRequires: vulkan-loader-devel BuildRequires: wget BuildRequires: which @@ -157,6 +159,7 @@ Requires: libX11 >= 1.7.3.1 Requires: numactl-libs >= 2.0.14 Requires: openssl >= 3.0.2 Requires: pulseaudio-libs >= 10.0 +Requires: vulkan-loader %endif %if 0%{?suse_version} @@ -173,6 +176,7 @@ Requires: libX11-6 Requires: libnuma1 Requires: libopenssl3 Requires: libpulse0 +Requires: vulkan-loader %endif %description diff --git a/packaging/sunshine.rb b/packaging/sunshine.rb index 5ff104944fe..db133057c84 100644 --- a/packaging/sunshine.rb +++ b/packaging/sunshine.rb @@ -97,6 +97,8 @@ class Sunshine < Formula depends_on "pipewire" depends_on "pulseaudio" depends_on "systemd" + depends_on "vulkan-headers" + depends_on "vulkan-loader" depends_on "wayland" # Jinja2 is required at build time by the glad OpenGL/EGL loader generator (Linux only). diff --git a/scripts/linux_build.sh b/scripts/linux_build.sh index e950bd4d011..c60cd4a5f79 100755 --- a/scripts/linux_build.sh +++ b/scripts/linux_build.sh @@ -195,6 +195,8 @@ function add_arch_deps() { 'python-jinja' # glad OpenGL/EGL loader generator 'python-setuptools' # glad OpenGL/EGL loader generated, v2.0.0 'udev' + 'vulkan-headers' + 'vulkan-icd-loader' 'wayland' ) @@ -249,6 +251,7 @@ function add_debian_based_deps() { "libxfixes-dev" # X11 "libxrandr-dev" # X11 "libxtst-dev" # X11 + "libvulkan-dev" # Vulkan "ninja-build" "npm" # web-ui "python3-jinja2" # glad OpenGL/EGL loader generator @@ -332,6 +335,8 @@ function add_fedora_deps() { "python3-jinja2" # glad OpenGL/EGL loader generator "python3-setuptools" # glad OpenGL/EGL loader generated, v2.0.0 "rpm-build" # if you want to build an RPM binary package + "vulkan-headers" + "vulkan-loader-devel" "wget" # necessary for cuda install with `run` file "which" # necessary for cuda install with `run` file "xorg-x11-server-Xvfb" # necessary for headless unit testing diff --git a/src/config.cpp b/src/config.cpp index 47475a04b4d..bdaabae0e6b 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -490,6 +490,10 @@ namespace config { {}, // encoder {}, // adapter_name {}, // output_name + { + 2, // vk.tune (default: ll - low latency) + 3, // vk.rc_mode (default: vbr) + }, { video_t::dd_t::config_option_e::disabled, // configuration_option @@ -1141,6 +1145,8 @@ namespace config { string_f(vars, "encoder", video.encoder); string_f(vars, "adapter_name", video.adapter_name); string_f(vars, "output_name", video.output_name); + int_f(vars, "vk_tune", video.vk.tune); + int_f(vars, "vk_rc_mode", video.vk.rc_mode); generic_f(vars, "dd_configuration_option", video.dd.configuration_option, dd::config_option_from_view); generic_f(vars, "dd_resolution_option", video.dd.resolution_option, dd::resolution_option_from_view); diff --git a/src/config.h b/src/config.h index 6e4f001b707..c1f56f83d54 100644 --- a/src/config.h +++ b/src/config.h @@ -84,6 +84,10 @@ namespace config { std::string encoder; std::string adapter_name; std::string output_name; + struct { + int tune; // 0=default, 1=hq, 2=ll, 3=ull + int rc_mode; // 0=auto, 1=cqp, 2=cbr, 3=vbr + } vk; struct dd_t { struct workarounds_t { diff --git a/src/platform/common.h b/src/platform/common.h index e334acf377b..a114af709e3 100644 --- a/src/platform/common.h +++ b/src/platform/common.h @@ -232,6 +232,7 @@ namespace platf { dxgi, ///< DXGI cuda, ///< CUDA videotoolbox, ///< VideoToolbox + vulkan, ///< Vulkan unknown ///< Unknown }; diff --git a/src/platform/linux/kmsgrab.cpp b/src/platform/linux/kmsgrab.cpp index c395791cea6..a10520b8fc9 100644 --- a/src/platform/linux/kmsgrab.cpp +++ b/src/platform/linux/kmsgrab.cpp @@ -27,6 +27,7 @@ #include "src/utility.h" #include "src/video.h" #include "vaapi.h" +#include "vulkan_encode.h" #include "wayland.h" using namespace std::literals; @@ -1246,6 +1247,12 @@ namespace platf { } #endif +#ifdef SUNSHINE_BUILD_VULKAN + if (mem_type == mem_type_e::vulkan) { + return vk::make_avcodec_encode_device_ram(width, height); + } +#endif + #ifdef SUNSHINE_BUILD_CUDA if (mem_type == mem_type_e::cuda) { return cuda::make_avcodec_encode_device(width, height, false); @@ -1379,6 +1386,12 @@ namespace platf { } #endif +#ifdef SUNSHINE_BUILD_VULKAN + if (mem_type == mem_type_e::vulkan) { + return vk::make_avcodec_encode_device_vram(width, height, img_offset_x, img_offset_y); + } +#endif + #ifdef SUNSHINE_BUILD_CUDA if (mem_type == mem_type_e::cuda) { return cuda::make_avcodec_gl_encode_device(width, height, img_offset_x, img_offset_y); @@ -1524,7 +1537,7 @@ namespace platf { } // namespace kms std::shared_ptr kms_display(mem_type_e hwdevice_type, const std::string &display_name, const ::video::config_t &config) { - if (hwdevice_type == mem_type_e::vaapi || hwdevice_type == mem_type_e::cuda) { + if (hwdevice_type == mem_type_e::vaapi || hwdevice_type == mem_type_e::cuda || hwdevice_type == mem_type_e::vulkan) { auto disp = std::make_shared(hwdevice_type); if (!disp->init(display_name, config)) { diff --git a/src/platform/linux/portalgrab.cpp b/src/platform/linux/portalgrab.cpp index 32ee0741933..ab225294d67 100644 --- a/src/platform/linux/portalgrab.cpp +++ b/src/platform/linux/portalgrab.cpp @@ -29,6 +29,7 @@ #include "src/platform/common.h" #include "src/video.h" #include "vaapi.h" +#include "vulkan_encode.h" #include "wayland.h" #if !defined(__FreeBSD__) @@ -877,6 +878,7 @@ namespace portal { // On hybrid GPU systems (Intel+NVIDIA), DMA-BUFs come from the Intel GPU and cannot // be imported into CUDA, so we fall back to memory buffers in that case. bool use_dmabuf = n_dmabuf_infos > 0 && (mem_type == platf::mem_type_e::vaapi || + mem_type == platf::mem_type_e::vulkan || (mem_type == platf::mem_type_e::cuda && display_is_nvidia)); if (use_dmabuf) { for (int i = 0; i < n_dmabuf_infos; i++) { @@ -1429,6 +1431,12 @@ namespace portal { } #endif +#ifdef SUNSHINE_BUILD_VULKAN + if (mem_type == platf::mem_type_e::vulkan) { + return vk::make_avcodec_encode_device_vram(width, height, 0, 0); + } +#endif + #ifdef SUNSHINE_BUILD_CUDA if (mem_type == platf::mem_type_e::cuda) { if (display_is_nvidia && n_dmabuf_infos > 0) { @@ -1612,7 +1620,7 @@ namespace portal { namespace platf { std::shared_ptr portal_display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config) { using enum platf::mem_type_e; - if (hwdevice_type != system && hwdevice_type != vaapi && hwdevice_type != cuda) { + if (hwdevice_type != system && hwdevice_type != vaapi && hwdevice_type != cuda && hwdevice_type != vulkan) { BOOST_LOG(error) << "Could not initialize display with the given hw device type."sv; return nullptr; } diff --git a/src/platform/linux/vulkan_encode.cpp b/src/platform/linux/vulkan_encode.cpp new file mode 100644 index 00000000000..5d80d6bc261 --- /dev/null +++ b/src/platform/linux/vulkan_encode.cpp @@ -0,0 +1,266 @@ +/** + * @file src/platform/linux/vulkan_encode.cpp + * @brief FFmpeg Vulkan encoder with zero-copy DMA-BUF import. + */ + +#include +#include +#include + +extern "C" { +#include +#include +#include +} + +#include + +#include "vulkan_encode.h" +#include "graphics.h" +#include "src/config.h" +#include "src/logging.h" +#include "misc.h" + +using namespace std::literals; + +namespace vk { + + class vk_vram_t: public platf::avcodec_encode_device_t { + public: + ~vk_vram_t() = default; + + int init(int in_width, int in_height, file_t &&render_device, int in_offset_x = 0, int in_offset_y = 0) { + file = std::move(render_device); + width = in_width; + height = in_height; + offset_x = in_offset_x; + offset_y = in_offset_y; + + if (!gbm::create_device) { + BOOST_LOG(warning) << "libgbm not initialized"sv; + return -1; + } + + this->data = (void *) vulkan_init_avcodec_hardware_input_buffer; + + gbm.reset(gbm::create_device(file.el)); + if (!gbm) { + BOOST_LOG(error) << "Couldn't create GBM device"sv; + return -1; + } + + display = egl::make_display(gbm.get()); + if (!display) return -1; + + auto ctx_opt = egl::make_ctx(display.get()); + if (!ctx_opt) return -1; + ctx = std::move(*ctx_opt); + + return 0; + } + + int set_frame(AVFrame *frame, AVBufferRef *hw_frames_ctx_buf) override { + this->hwframe.reset(frame); + this->frame = frame; + this->hw_frames_ctx = hw_frames_ctx_buf; + + auto *frames_ctx = (AVHWFramesContext *) hw_frames_ctx_buf->data; + auto *dev_ctx = (AVHWDeviceContext *) frames_ctx->device_ref->data; + vk_dev_ctx = (AVVulkanDeviceContext *) dev_ctx->hwctx; + vk_dev = vk_dev_ctx->act_dev; + + // Load Vulkan extension functions + if (!vkGetMemoryFdKHR_fn) { + vkGetMemoryFdKHR_fn = (PFN_vkGetMemoryFdKHR)vkGetDeviceProcAddr(vk_dev, "vkGetMemoryFdKHR"); + } + + // Create sws for RGB->NV12 conversion with scaling from capture to encode resolution + auto sws_opt = egl::sws_t::make(width, height, frame->width, frame->height, frames_ctx->sw_format); + if (!sws_opt) return -1; + sws = std::move(*sws_opt); + + return 0; + } + + void apply_colorspace() override { + sws.apply_colorspace(colorspace); + } + + void init_hwframes(AVHWFramesContext *frames) override { + frames->initial_pool_size = 4; + + // Request linear tiling for simpler interop + auto *vk_frames = (AVVulkanFramesContext *)frames->hwctx; + vk_frames->tiling = VK_IMAGE_TILING_LINEAR; + vk_frames->usage = (VkImageUsageFlagBits)(VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT); + } + + int convert(platf::img_t &img) override { + auto &descriptor = (egl::img_descriptor_t &) img; + + // Get Vulkan frame + if (!frame->buf[0]) { + if (av_hwframe_get_buffer(hw_frames_ctx, frame, 0) < 0) { + BOOST_LOG(error) << "Failed to get Vulkan frame"sv; + return -1; + } + } + + // Import source RGB texture + if (descriptor.sequence == 0) { + rgb = egl::create_blank(img); + } else if (descriptor.sequence > sequence) { + sequence = descriptor.sequence; + rgb = egl::rgb_t {}; + auto rgb_opt = egl::import_source(display.get(), descriptor.sd); + if (!rgb_opt) return -1; + rgb = std::move(*rgb_opt); + } + + // Setup Vulkan→EGL zero-copy interop if needed + if (!nv12_imported) { + if (!setup_vulkan_egl_interop()) { + BOOST_LOG(error) << "Failed to setup Vulkan-EGL interop"sv; + return -1; + } + nv12_imported = true; + } + + // Render RGB→NV12 directly into Vulkan memory via EGL (zero-copy) + sws.load_vram(descriptor, offset_x, offset_y, rgb->tex[0]); + sws.convert(nv12->buf); + gl::ctx.Finish(); // Ensure EGL rendering completes before Vulkan encoder reads + + return 0; + } + + private: + bool setup_vulkan_egl_interop() { + if (!vkGetMemoryFdKHR_fn) { + BOOST_LOG(warning) << "vkGetMemoryFdKHR not available"sv; + return false; + } + + AVVkFrame *vk_frame = (AVVkFrame *) frame->data[0]; + if (!vk_frame) { + BOOST_LOG(warning) << "No Vulkan frame"sv; + return false; + } + + // Export the first memory object + VkMemoryGetFdInfoKHR fd_info = {}; + fd_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR; + fd_info.memory = vk_frame->mem[0]; + fd_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; + + int fd = -1; + VkResult res = vkGetMemoryFdKHR_fn(vk_dev, &fd_info, &fd); + if (res != VK_SUCCESS || fd < 0) { + BOOST_LOG(warning) << "vkGetMemoryFdKHR failed: " << res; + return false; + } + + std::array fds; + fds[0].el = fd; + fds[1].el = dup(fd); // Both planes use same memory + + egl::surface_descriptor_t sds[2] = {}; + + // Count images and memories for multiplane detection + int num_imgs = 0, num_mems = 0; + for (int i = 0; i < AV_NUM_DATA_POINTERS; i++) { + if (vk_frame->img[i]) num_imgs++; + if (vk_frame->mem[i]) num_mems++; + } + bool multiplane_single_image = (num_imgs == 1 && num_mems == 1); + + for (int i = 0; i < 2; i++) { + auto &sd = sds[i]; + sd.fourcc = (i == 0) ? DRM_FORMAT_R8 : DRM_FORMAT_GR88; + sd.width = frame->width >> (i ? 1 : 0); + sd.height = frame->height >> (i ? 1 : 0); + sd.modifier = DRM_FORMAT_MOD_LINEAR; + sd.fds[0] = fds[i].el; + sd.fds[1] = sd.fds[2] = sd.fds[3] = -1; + + VkImageSubresource subres = {}; + if (multiplane_single_image) { + subres.aspectMask = (i == 0) ? VK_IMAGE_ASPECT_PLANE_0_BIT : VK_IMAGE_ASPECT_PLANE_1_BIT; + } else { + subres.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + } + + VkSubresourceLayout layout; + vkGetImageSubresourceLayout(vk_dev, vk_frame->img[multiplane_single_image ? 0 : i], &subres, &layout); + sd.pitches[0] = layout.rowPitch; + sd.offsets[0] = layout.offset; + } + + // Import into EGL + auto nv12_opt = egl::import_target(display.get(), std::move(fds), sds[0], sds[1]); + if (!nv12_opt) { + BOOST_LOG(warning) << "Failed to import Vulkan frame into EGL"sv; + return false; + } + nv12 = std::move(*nv12_opt); + return true; + } + + static int vulkan_init_avcodec_hardware_input_buffer(platf::avcodec_encode_device_t *, AVBufferRef **hw_device_buf) { + return av_hwdevice_ctx_create(hw_device_buf, AV_HWDEVICE_TYPE_VULKAN, nullptr, nullptr, 0); + } + + int width = 0, height = 0; + int offset_x = 0, offset_y = 0; + AVBufferRef *hw_frames_ctx = nullptr; + frame_t hwframe; + + file_t file; + gbm::gbm_t gbm; + egl::display_t display; + egl::ctx_t ctx; + egl::sws_t sws; + egl::nv12_t nv12; + egl::rgb_t rgb; + std::uint64_t sequence = 0; + bool nv12_imported = false; + + // Vulkan device state (from FFmpeg) + VkDevice vk_dev = VK_NULL_HANDLE; + AVVulkanDeviceContext *vk_dev_ctx = nullptr; + + PFN_vkGetMemoryFdKHR vkGetMemoryFdKHR_fn = nullptr; + }; + + int vulkan_init_avcodec_hardware_input_buffer(platf::avcodec_encode_device_t *, AVBufferRef **hw_device_buf) { + return av_hwdevice_ctx_create(hw_device_buf, AV_HWDEVICE_TYPE_VULKAN, nullptr, nullptr, 0); + } + + bool validate() { + if (!avcodec_find_encoder_by_name("h264_vulkan") && !avcodec_find_encoder_by_name("hevc_vulkan")) + return false; + AVBufferRef *dev = nullptr; + if (av_hwdevice_ctx_create(&dev, AV_HWDEVICE_TYPE_VULKAN, nullptr, nullptr, 0) < 0) + return false; + av_buffer_unref(&dev); + return true; + } + + std::unique_ptr make_avcodec_encode_device_vram(int w, int h, int offset_x, int offset_y) { + auto render_device = config::video.adapter_name.empty() ? "/dev/dri/renderD128" : config::video.adapter_name.c_str(); + file_t file = open(render_device, O_RDWR); + if (file.el < 0) { + BOOST_LOG(error) << "Failed to open render device: "sv << render_device; + return nullptr; + } + auto dev = std::make_unique(); + if (dev->init(w, h, std::move(file), offset_x, offset_y) < 0) return nullptr; + return dev; + } + + std::unique_ptr make_avcodec_encode_device_ram(int, int) { + return nullptr; + } + +} // namespace vk diff --git a/src/platform/linux/vulkan_encode.h b/src/platform/linux/vulkan_encode.h new file mode 100644 index 00000000000..db887f504c7 --- /dev/null +++ b/src/platform/linux/vulkan_encode.h @@ -0,0 +1,36 @@ +/** + * @file src/platform/linux/vulkan_encode.h + * @brief Declarations for FFmpeg Vulkan Video encoder. + */ +#pragma once + +#include "src/platform/common.h" + +extern "C" struct AVBufferRef; + +namespace vk { + + /** + * @brief Initialize Vulkan hardware device for FFmpeg encoding. + * @param encode_device The encode device (vk_t). + * @param hw_device_buf Output hardware device buffer. + * @return 0 on success, negative on error. + */ + int vulkan_init_avcodec_hardware_input_buffer(platf::avcodec_encode_device_t *encode_device, AVBufferRef **hw_device_buf); + + /** + * @brief Create a Vulkan encode device for RAM capture. + */ + std::unique_ptr make_avcodec_encode_device_ram(int width, int height); + + /** + * @brief Create a Vulkan encode device for VRAM capture. + */ + std::unique_ptr make_avcodec_encode_device_vram(int width, int height, int offset_x, int offset_y); + + /** + * @brief Check if FFmpeg Vulkan Video encoding is available. + */ + bool validate(); + +} // namespace vk diff --git a/src/video.cpp b/src/video.cpp index 6b2b635277c..f0d067a94be 100644 --- a/src/video.cpp +++ b/src/video.cpp @@ -122,6 +122,9 @@ namespace video { util::Either vaapi_init_avcodec_hardware_input_buffer(platf::avcodec_encode_device_t *); util::Either cuda_init_avcodec_hardware_input_buffer(platf::avcodec_encode_device_t *); util::Either vt_init_avcodec_hardware_input_buffer(platf::avcodec_encode_device_t *); +#ifdef SUNSHINE_BUILD_VULKAN + util::Either vulkan_init_avcodec_hardware_input_buffer(platf::avcodec_encode_device_t *); +#endif class avcodec_software_encode_device_t: public platf::avcodec_encode_device_t { public: @@ -1012,7 +1015,75 @@ namespace video { // RC buffer size will be set in platform code if supported LIMITED_GOP_SIZE | PARALLEL_ENCODING | NO_RC_BUF_LIMIT }; -#endif + +#ifdef SUNSHINE_BUILD_VULKAN + encoder_t vulkan { + "vulkan"sv, + std::make_unique( + AV_HWDEVICE_TYPE_VULKAN, + AV_HWDEVICE_TYPE_NONE, + AV_PIX_FMT_VULKAN, + AV_PIX_FMT_NV12, + AV_PIX_FMT_P010, + AV_PIX_FMT_NONE, + AV_PIX_FMT_NONE, + vulkan_init_avcodec_hardware_input_buffer + ), + { + // AV1 + { + {"idr_interval"s, std::numeric_limits::max()}, + {"tune"s, &config::video.vk.tune}, + {"rc_mode"s, &config::video.vk.rc_mode}, + {"usage"s, "stream"s}, + {"content"s, "rendered"s}, + {"async_depth"s, 1}, + }, + {}, // SDR-specific options + {}, // HDR-specific options + {}, // YUV444 SDR-specific options + {}, // YUV444 HDR-specific options + {}, // Fallback options + "av1_vulkan"s, + }, + { + // HEVC + { + {"idr_interval"s, std::numeric_limits::max()}, + {"tune"s, &config::video.vk.tune}, + {"rc_mode"s, &config::video.vk.rc_mode}, + {"usage"s, "stream"s}, + {"content"s, "rendered"s}, + {"async_depth"s, 1}, + }, + {}, // SDR-specific options + {}, // HDR-specific options + {}, // YUV444 SDR-specific options + {}, // YUV444 HDR-specific options + {}, // Fallback options + "hevc_vulkan"s, + }, + { + // H.264 + { + {"idr_interval"s, std::numeric_limits::max()}, + {"tune"s, &config::video.vk.tune}, + {"rc_mode"s, &config::video.vk.rc_mode}, + {"usage"s, "stream"s}, + {"content"s, "rendered"s}, + {"async_depth"s, 1}, + }, + {}, // SDR-specific options + {}, // HDR-specific options + {}, // YUV444 SDR-specific options + {}, // YUV444 HDR-specific options + {}, // Fallback options + "h264_vulkan"s, + }, + LIMITED_GOP_SIZE | PARALLEL_ENCODING + }; +#endif // SUNSHINE_BUILD_VULKAN +#endif // linux #ifdef __APPLE__ encoder_t videotoolbox { @@ -1092,6 +1163,9 @@ namespace video { &mediafoundation, #endif #if defined(__linux__) || defined(linux) || defined(__linux) || defined(__FreeBSD__) +#ifdef SUNSHINE_BUILD_VULKAN + &vulkan, +#endif &vaapi, #endif #ifdef __APPLE__ @@ -2935,6 +3009,43 @@ namespace video { return hw_device_buf; } +#ifdef SUNSHINE_BUILD_VULKAN + typedef int (*vulkan_init_avcodec_hardware_input_buffer_fn)(platf::avcodec_encode_device_t *encode_device, AVBufferRef **hw_device_buf); + + util::Either vulkan_init_avcodec_hardware_input_buffer(platf::avcodec_encode_device_t *encode_device) { + avcodec_buffer_t hw_device_buf; + + if (encode_device && encode_device->data) { + if (((vulkan_init_avcodec_hardware_input_buffer_fn) encode_device->data)(encode_device, &hw_device_buf)) { + return -1; + } + return hw_device_buf; + } + + // Try render device path first (like VAAPI does), then fallback to device indices + auto render_device = config::video.adapter_name.empty() ? "/dev/dri/renderD128" : config::video.adapter_name.c_str(); + + auto status = av_hwdevice_ctx_create(&hw_device_buf, AV_HWDEVICE_TYPE_VULKAN, render_device, nullptr, 0); + if (status >= 0) { + BOOST_LOG(info) << "Using Vulkan device: "sv << render_device; + return hw_device_buf; + } + + // Fallback: try device indices for multi-GPU systems + const char *devices[] = {"1", "0", "2", "3", nullptr}; + for (int i = 0; devices[i]; i++) { + status = av_hwdevice_ctx_create(&hw_device_buf, AV_HWDEVICE_TYPE_VULKAN, devices[i], nullptr, 0); + if (status >= 0) { + BOOST_LOG(info) << "Using Vulkan device index: "sv << devices[i]; + return hw_device_buf; + } + } + + BOOST_LOG(error) << "Failed to create a Vulkan device"sv; + return -1; + } +#endif + util::Either cuda_init_avcodec_hardware_input_buffer(platf::avcodec_encode_device_t *encode_device) { avcodec_buffer_t hw_device_buf; @@ -3032,6 +3143,10 @@ namespace video { return platf::mem_type_e::dxgi; case AV_HWDEVICE_TYPE_VAAPI: return platf::mem_type_e::vaapi; +#ifdef SUNSHINE_BUILD_VULKAN + case AV_HWDEVICE_TYPE_VULKAN: + return platf::mem_type_e::vulkan; +#endif case AV_HWDEVICE_TYPE_CUDA: return platf::mem_type_e::cuda; case AV_HWDEVICE_TYPE_NONE: diff --git a/src_assets/common/assets/web/config.html b/src_assets/common/assets/web/config.html index b391e3e7470..714c4de71ac 100644 --- a/src_assets/common/assets/web/config.html +++ b/src_assets/common/assets/web/config.html @@ -325,6 +325,14 @@

{{ $t('config.configuration') }}

"vt_realtime": "enabled", }, }, + { + id: "vulkan", + name: "Vulkan Encoder", + options: { + "vk_tune": 2, + "vk_rc_mode": 3, + }, + }, { id: "vaapi", name: "VA-API Encoder", @@ -383,7 +391,7 @@

{{ $t('config.configuration') }}

var app = document.getElementById("app"); if (this.platform === "windows") { this.tabs = this.tabs.filter((el) => { - return el.id !== "vt" && el.id !== "vaapi"; + return el.id !== "vt" && el.id !== "vaapi" && el.id !== "vulkan"; }); } if (this.platform === "freebsd" || this.platform === "linux") { @@ -393,7 +401,7 @@

{{ $t('config.configuration') }}

} if (this.platform === "macos") { this.tabs = this.tabs.filter((el) => { - return el.id !== "amd" && el.id !== "nv" && el.id !== "qsv" && el.id !== "vaapi"; + return el.id !== "amd" && el.id !== "nv" && el.id !== "qsv" && el.id !== "vaapi" && el.id !== "vulkan"; }); } @@ -436,6 +444,7 @@

{{ $t('config.configuration') }}

'amd': 'Gpu', 'qsv': 'Gpu', 'vaapi': 'Gpu', + 'vulkan': 'Gpu', 'vt': 'Gpu', 'sw': 'Cpu', }; diff --git a/src_assets/common/assets/web/configs/tabs/Advanced.vue b/src_assets/common/assets/web/configs/tabs/Advanced.vue index d63d095f2d9..7e86e98d03b 100644 --- a/src_assets/common/assets/web/configs/tabs/Advanced.vue +++ b/src_assets/common/assets/web/configs/tabs/Advanced.vue @@ -97,10 +97,12 @@ const config = ref(props.config) - - From 1c620900d76ecb6bce819e7ed4f2412b2ec3a780 Mon Sep 17 00:00:00 2001 From: neatnoise Date: Sat, 14 Mar 2026 17:58:43 +0100 Subject: [PATCH 17/29] vulkan: revert rc_max_rate cap to match Mar 8 overshoot state Remove the 120% rc_max_rate cap added in 5d1ee1a8. Both vulkan-pr and vulkan+control now share the same overshoot fix: only rc_min_rate=0 in VBR mode. --- src/platform/linux/vulkan_encode.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/platform/linux/vulkan_encode.cpp b/src/platform/linux/vulkan_encode.cpp index 0a70888398f..ba313be600b 100644 --- a/src/platform/linux/vulkan_encode.cpp +++ b/src/platform/linux/vulkan_encode.cpp @@ -123,10 +123,6 @@ namespace vk { // on complex frames. if (config::video.vk.rc_mode == 4) { ctx->rc_min_rate = 0; - // Cap maxBitrate to 120% of target to limit VBR overshoots. - // FFmpeg's vulkan_encode passes rc_max_rate as maxBitrate to the driver; - // without this, maxBitrate == averageBitrate gives the driver no ceiling. - ctx->rc_max_rate = ctx->bit_rate * 120 / 100; } } From 779d5f2bff2e7d08b678cf98850b0e73bf7c36f2 Mon Sep 17 00:00:00 2001 From: neatnoise Date: Sat, 14 Mar 2026 18:00:51 +0100 Subject: [PATCH 18/29] vulkan: remove NO_RC_BUF_LIMIT from h264_vulkan to match Mar 8 state --- src/video.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video.cpp b/src/video.cpp index 284f3f68667..d277691c902 100644 --- a/src/video.cpp +++ b/src/video.cpp @@ -1082,7 +1082,7 @@ namespace video { {}, // Fallback options "h264_vulkan"s, }, - LIMITED_GOP_SIZE | PARALLEL_ENCODING | NO_RC_BUF_LIMIT + LIMITED_GOP_SIZE | PARALLEL_ENCODING }; #endif // SUNSHINE_BUILD_VULKAN #endif // linux From bf7b4840fd37ef0f5ef4d2f5030b739b908436be Mon Sep 17 00:00:00 2001 From: neatnoise Date: Tue, 17 Mar 2026 22:15:02 +0100 Subject: [PATCH 19/29] fix: resolve CI lint and test failures for Vulkan encoder - cmake-lint: remove set(Vulkan_FOUND OFF), use SUNSHINE_ENABLE_VULKAN guard - clang-format: apply formatting to vulkan_encode.cpp and config.h - trailing whitespace: clean blank line in video.cpp - docs: add Vulkan Encoder section with vk_tune and vk_rc_mode - tests: add Vulkan Encoder tab-to-section mapping --- cmake/compile_definitions/linux.cmake | 4 +- docs/configuration.md | 95 ++++++ src/config.h | 2 +- src/platform/linux/vulkan_encode.cpp | 292 ++++++++++++------ src/video.cpp | 2 +- tests/integration/test_config_consistency.cpp | 1 + 6 files changed, 289 insertions(+), 107 deletions(-) diff --git a/cmake/compile_definitions/linux.cmake b/cmake/compile_definitions/linux.cmake index 7eddefbd26d..c6b3e73dcdf 100644 --- a/cmake/compile_definitions/linux.cmake +++ b/cmake/compile_definitions/linux.cmake @@ -123,10 +123,8 @@ endif() # vulkan video encoding (via FFmpeg) if(${SUNSHINE_ENABLE_VULKAN}) find_package(Vulkan REQUIRED) -else() - set(Vulkan_FOUND OFF) endif() -if(Vulkan_FOUND) +if(SUNSHINE_ENABLE_VULKAN AND Vulkan_FOUND) list(APPEND SUNSHINE_DEFINITIONS SUNSHINE_BUILD_VULKAN=1) include_directories(SYSTEM ${Vulkan_INCLUDE_DIRS}) list(APPEND PLATFORM_LIBRARIES ${Vulkan_LIBRARIES}) diff --git a/docs/configuration.md b/docs/configuration.md index 12e5c242dea..c661e955e1b 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -2925,6 +2925,101 @@ editing the `conf` file in a text editor. Use the examples as reference. +## Vulkan Encoder + +### vk_tune + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Description + Encoder tuning preset. Low latency modes reduce encoding delay at the cost of quality. + @note{This option only applies when using Vulkan [encoder](#encoder).} +
Default@code{} + 2 + @endcode
Example@code{} + vk_tune = 1 + @endcode
Options0 (default)Let the driver decide
1 (hq)High Quality
2 (ll)Low Latency
3 (ull)Ultra Low Latency
4 (lossless)Lossless
+ +### vk_rc_mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Description + Rate control mode for encoding. Auto lets the driver decide. + @note{This option only applies when using Vulkan [encoder](#encoder).} +
Default@code{} + 4 + @endcode
Example@code{} + vk_rc_mode = 2 + @endcode
Options0Auto (driver decides)
1CQP (Constant QP)
2CBR (Constant Bitrate)
4VBR (Variable Bitrate)
+ ## Software Encoder ### sw_preset diff --git a/src/config.h b/src/config.h index e0df5c9347b..44ade5a3685 100644 --- a/src/config.h +++ b/src/config.h @@ -81,7 +81,7 @@ namespace config { } vaapi; struct { - int tune; // 0=default, 1=hq, 2=ll, 3=ull, 4=lossless + int tune; // 0=default, 1=hq, 2=ll, 3=ull, 4=lossless int rc_mode; // 0=driver, 1=cqp, 2=cbr, 4=vbr } vk; diff --git a/src/platform/linux/vulkan_encode.cpp b/src/platform/linux/vulkan_encode.cpp index ba313be600b..86983397272 100644 --- a/src/platform/linux/vulkan_encode.cpp +++ b/src/platform/linux/vulkan_encode.cpp @@ -3,11 +3,11 @@ * @brief Vulkan-native encoder: DMA-BUF -> Vulkan compute (RGB->YUV) -> Vulkan Video encode. * No EGL/GL dependency — all GPU work stays in a single Vulkan queue. */ +#include +#include #include #include -#include #include -#include extern "C" { #include @@ -15,14 +15,14 @@ extern "C" { #include } -#include - -#include "vulkan_encode.h" #include "graphics.h" +#include "shaders/rgb2yuv.spv.h" #include "src/config.h" #include "src/logging.h" #include "src/video_colorspace.h" -#include "shaders/rgb2yuv.spv.h" +#include "vulkan_encode.h" + +#include using namespace std::literals; @@ -32,7 +32,9 @@ namespace vk { // Returns the index as a string (e.g. "1"), or empty string if no match. static std::string find_vulkan_index_for_render_node(const char *render_path) { struct stat node_stat; - if (stat(render_path, &node_stat) < 0) return {}; + if (stat(render_path, &node_stat) < 0) { + return {}; + } auto target_major = major(node_stat.st_rdev); auto target_minor = minor(node_stat.st_rdev); @@ -42,7 +44,9 @@ namespace vk { VkInstanceCreateInfo ci = {VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO}; ci.pApplicationInfo = &app; VkInstance inst = VK_NULL_HANDLE; - if (vkCreateInstance(&ci, nullptr, &inst) != VK_SUCCESS) return {}; + if (vkCreateInstance(&ci, nullptr, &inst) != VK_SUCCESS) { + return {}; + } uint32_t count = 0; vkEnumeratePhysicalDevices(inst, &count, nullptr); @@ -55,7 +59,7 @@ namespace vk { VkPhysicalDeviceProperties2 props2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; props2.pNext = &drm; vkGetPhysicalDeviceProperties2(devs[i], &props2); - if (drm.hasRender && drm.renderMajor == (int64_t)target_major && drm.renderMinor == (int64_t)target_minor) { + if (drm.hasRender && drm.renderMajor == (int64_t) target_major && drm.renderMinor == (int64_t) target_minor) { result = std::to_string(i); break; } @@ -66,19 +70,20 @@ namespace vk { static int create_vulkan_hwdevice(AVBufferRef **hw_device_buf) { // Resolve render device path to Vulkan device index - if (auto render_path = config::video.adapter_name.empty() ? "/dev/dri/renderD128" : config::video.adapter_name; - render_path[0] == '/') { - if (auto idx = find_vulkan_index_for_render_node(render_path.c_str()); - !idx.empty() && av_hwdevice_ctx_create(hw_device_buf, AV_HWDEVICE_TYPE_VULKAN, idx.c_str(), nullptr, 0) >= 0) + if (auto render_path = config::video.adapter_name.empty() ? "/dev/dri/renderD128" : config::video.adapter_name; render_path[0] == '/') { + if (auto idx = find_vulkan_index_for_render_node(render_path.c_str()); !idx.empty() && av_hwdevice_ctx_create(hw_device_buf, AV_HWDEVICE_TYPE_VULKAN, idx.c_str(), nullptr, 0) >= 0) { return 0; + } } else { // Non-path: treat as device name substring or numeric index - if (av_hwdevice_ctx_create(hw_device_buf, AV_HWDEVICE_TYPE_VULKAN, render_path.c_str(), nullptr, 0) >= 0) + if (av_hwdevice_ctx_create(hw_device_buf, AV_HWDEVICE_TYPE_VULKAN, render_path.c_str(), nullptr, 0) >= 0) { return 0; + } } // Final fallback: let FFmpeg pick default - if (av_hwdevice_ctx_create(hw_device_buf, AV_HWDEVICE_TYPE_VULKAN, nullptr, nullptr, 0) >= 0) + if (av_hwdevice_ctx_create(hw_device_buf, AV_HWDEVICE_TYPE_VULKAN, nullptr, nullptr, 0) >= 0) { return 0; + } return -1; } @@ -95,11 +100,23 @@ namespace vk { std::array cursor_size; }; - // Helper to check VkResult - #define VK_CHECK(expr) do { VkResult _r = (expr); if (_r != VK_SUCCESS) { \ - BOOST_LOG(error) << #expr << " failed: " << _r; return -1; } } while(0) - #define VK_CHECK_BOOL(expr) do { VkResult _r = (expr); if (_r != VK_SUCCESS) { \ - BOOST_LOG(error) << #expr << " failed: " << _r; return false; } } while(0) +// Helper to check VkResult +#define VK_CHECK(expr) \ + do { \ + VkResult _r = (expr); \ + if (_r != VK_SUCCESS) { \ + BOOST_LOG(error) << #expr << " failed: " << _r; \ + return -1; \ + } \ + } while (0) +#define VK_CHECK_BOOL(expr) \ + do { \ + VkResult _r = (expr); \ + if (_r != VK_SUCCESS) { \ + BOOST_LOG(error) << #expr << " failed: " << _r; \ + return false; \ + } \ + } while (0) class vk_vram_t: public platf::avcodec_encode_device_t { public: @@ -163,8 +180,12 @@ namespace vk { vk_dev.getMemoryFdProperties = (PFN_vkGetMemoryFdPropertiesKHR) vkGetDeviceProcAddr(vk_dev.dev, "vkGetMemoryFdPropertiesKHR"); - if (!create_compute_pipeline()) return -1; - if (!create_command_resources()) return -1; + if (!create_compute_pipeline()) { + return -1; + } + if (!create_command_resources()) { + return -1; + } return 0; } @@ -182,12 +203,11 @@ namespace vk { void init_hwframes(AVHWFramesContext *frames) override { frames->initial_pool_size = 4; - auto *vk_frames = (AVVulkanFramesContext *)frames->hwctx; + auto *vk_frames = (AVVulkanFramesContext *) frames->hwctx; vk_frames->tiling = VK_IMAGE_TILING_OPTIMAL; - vk_frames->usage = (VkImageUsageFlagBits)( - VK_IMAGE_USAGE_STORAGE_BIT | - VK_IMAGE_USAGE_TRANSFER_DST_BIT | - VK_IMAGE_USAGE_SAMPLED_BIT); + vk_frames->usage = (VkImageUsageFlagBits) (VK_IMAGE_USAGE_STORAGE_BIT | + VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT); } int convert(platf::img_t &img) override { @@ -216,11 +236,15 @@ namespace vk { descriptors_dirty = true; } - if (src.image == VK_NULL_HANDLE) return -1; + if (src.image == VK_NULL_HANDLE) { + return -1; + } // Setup Y/UV image views for the encoder target (once) if (!target.views_created) { - if (!create_target_views()) return -1; + if (!create_target_views()) { + return -1; + } target.views_created = true; descriptors_dirty = true; } @@ -233,8 +257,9 @@ namespace vk { if (descriptor.data && descriptor.serial != cursor_serial) { cursor_serial = descriptor.serial; - if (!create_cursor_image(descriptor.src_w, descriptor.src_h, descriptor.data)) + if (!create_cursor_image(descriptor.src_w, descriptor.src_h, descriptor.data)) { return -1; + } update_descriptors(); descriptors_dirty = false; } @@ -248,12 +273,12 @@ namespace vk { push.dst_size[1] = frame->height; if (descriptor.data) { - float scale_x = (float)frame->width / width; - float scale_y = (float)frame->height / height; - push.cursor_pos[0] = (int32_t)((descriptor.x - offset_x) * scale_x); - push.cursor_pos[1] = (int32_t)((descriptor.y - offset_y) * scale_y); - push.cursor_size[0] = (int32_t)(descriptor.width * scale_x); - push.cursor_size[1] = (int32_t)(descriptor.height * scale_y); + float scale_x = (float) frame->width / width; + float scale_y = (float) frame->height / height; + push.cursor_pos[0] = (int32_t) ((descriptor.x - offset_x) * scale_x); + push.cursor_pos[1] = (int32_t) ((descriptor.y - offset_y) * scale_y); + push.cursor_size[0] = (int32_t) (descriptor.width * scale_x); + push.cursor_size[1] = (int32_t) (descriptor.height * scale_y); } else { push.cursor_size[0] = 0; } @@ -326,7 +351,9 @@ namespace vk { sampler_ci.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; VK_CHECK_BOOL(vkCreateSampler(vk_dev.dev, &sampler_ci, nullptr, &compute.sampler)); - if (!create_cursor_image(1, 1, nullptr)) return false; + if (!create_cursor_image(1, 1, nullptr)) { + return false; + } return true; } @@ -349,13 +376,17 @@ namespace vk { static VkFormat drm_fourcc_to_vk_format(uint32_t fourcc) { switch (fourcc) { case DRM_FORMAT_XRGB8888: - case DRM_FORMAT_ARGB8888: return VK_FORMAT_B8G8R8A8_UNORM; + case DRM_FORMAT_ARGB8888: + return VK_FORMAT_B8G8R8A8_UNORM; case DRM_FORMAT_XBGR8888: - case DRM_FORMAT_ABGR8888: return VK_FORMAT_R8G8B8A8_UNORM; + case DRM_FORMAT_ABGR8888: + return VK_FORMAT_R8G8B8A8_UNORM; case DRM_FORMAT_XRGB2101010: - case DRM_FORMAT_ARGB2101010: return VK_FORMAT_A2R10G10B10_UNORM_PACK32; + case DRM_FORMAT_ARGB2101010: + return VK_FORMAT_A2R10G10B10_UNORM_PACK32; case DRM_FORMAT_XBGR2101010: - case DRM_FORMAT_ABGR2101010: return VK_FORMAT_A2B10G10R10_UNORM_PACK32; + case DRM_FORMAT_ABGR2101010: + return VK_FORMAT_A2B10G10R10_UNORM_PACK32; default: BOOST_LOG(warning) << "Unknown DRM fourcc 0x" << std::hex << fourcc << std::dec << ", assuming B8G8R8A8"; return VK_FORMAT_B8G8R8A8_UNORM; @@ -366,7 +397,9 @@ namespace vk { destroy_src_image(); int fd = dup(sd.fds[0]); - if (fd < 0) return false; + if (fd < 0) { + return false; + } // Query memory requirements for this DMA-BUF VkMemoryFdPropertiesKHR fd_props = {VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR}; @@ -380,7 +413,8 @@ namespace vk { std::array drm_layouts = {}; VkImageDrmFormatModifierExplicitCreateInfoEXT drm_ci = { - VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT}; + VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT + }; VkImageTiling tiling; if (sd.modifier != DRM_FORMAT_MOD_INVALID) { @@ -405,7 +439,7 @@ namespace vk { img_ci.pNext = &ext_ci; img_ci.imageType = VK_IMAGE_TYPE_2D; img_ci.format = vk_format; - img_ci.extent = {(uint32_t)sd.width, (uint32_t)sd.height, 1}; + img_ci.extent = {(uint32_t) sd.width, (uint32_t) sd.height, 1}; img_ci.mipLevels = 1; img_ci.arrayLayers = 1; img_ci.samples = VK_SAMPLE_COUNT_1_BIT; @@ -435,7 +469,8 @@ namespace vk { alloc_info.allocationSize = mem_req.size; alloc_info.memoryTypeIndex = find_memory_type( fd_props.memoryTypeBits ? fd_props.memoryTypeBits : mem_req.memoryTypeBits, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT + ); VkDeviceMemory src_mem = VK_NULL_HANDLE; res = vkAllocateMemory(vk_dev.dev, &alloc_info, nullptr, &src_mem); @@ -466,7 +501,7 @@ namespace vk { VkImageCreateInfo img_ci = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO}; img_ci.imageType = VK_IMAGE_TYPE_2D; img_ci.format = VK_FORMAT_B8G8R8A8_UNORM; - img_ci.extent = {(uint32_t)w, (uint32_t)h, 1}; + img_ci.extent = {(uint32_t) w, (uint32_t) h, 1}; img_ci.mipLevels = 1; img_ci.arrayLayers = 1; img_ci.samples = VK_SAMPLE_COUNT_1_BIT; @@ -479,8 +514,7 @@ namespace vk { vkGetImageMemoryRequirements(vk_dev.dev, cursor.image, &mem_req); VkMemoryAllocateInfo alloc = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO}; alloc.allocationSize = mem_req.size; - alloc.memoryTypeIndex = find_memory_type(mem_req.memoryTypeBits, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + alloc.memoryTypeIndex = find_memory_type(mem_req.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); VK_CHECK_BOOL(vkAllocateMemory(vk_dev.dev, &alloc, nullptr, &cursor.mem)); VK_CHECK_BOOL(vkBindImageMemory(vk_dev.dev, cursor.image, cursor.mem, 0)); @@ -490,8 +524,9 @@ namespace vk { VkImageSubresource subres = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0}; VkSubresourceLayout layout; vkGetImageSubresourceLayout(vk_dev.dev, cursor.image, &subres, &layout); - for (int y = 0; y < h; y++) - memcpy((uint8_t *)mapped + layout.offset + y * layout.rowPitch, pixels + y * w * 4, w * 4); + for (int y = 0; y < h; y++) { + memcpy((uint8_t *) mapped + layout.offset + y * layout.rowPitch, pixels + y * w * 4, w * 4); + } vkUnmapMemory(vk_dev.dev, cursor.mem); } @@ -508,21 +543,34 @@ namespace vk { } void destroy_cursor_image() { - if (cursor.view) { vkDestroyImageView(vk_dev.dev, cursor.view, nullptr); cursor.view = VK_NULL_HANDLE; } - if (cursor.image) { vkDestroyImage(vk_dev.dev, cursor.image, nullptr); cursor.image = VK_NULL_HANDLE; } - if (cursor.mem) { vkFreeMemory(vk_dev.dev, cursor.mem, nullptr); cursor.mem = VK_NULL_HANDLE; } + if (cursor.view) { + vkDestroyImageView(vk_dev.dev, cursor.view, nullptr); + cursor.view = VK_NULL_HANDLE; + } + if (cursor.image) { + vkDestroyImage(vk_dev.dev, cursor.image, nullptr); + cursor.image = VK_NULL_HANDLE; + } + if (cursor.mem) { + vkFreeMemory(vk_dev.dev, cursor.mem, nullptr); + cursor.mem = VK_NULL_HANDLE; + } } bool create_target_views() { auto *vk_frame = (AVVkFrame *) frame->data[0]; - if (!vk_frame) return false; + if (!vk_frame) { + return false; + } auto y_fmt = is_10bit ? VK_FORMAT_R16_UNORM : VK_FORMAT_R8_UNORM; auto uv_fmt = is_10bit ? VK_FORMAT_R16G16_UNORM : VK_FORMAT_R8G8_UNORM; // Detect multiplane vs multi-image layout int num_imgs = 0; - for (int i = 0; i < AV_NUM_DATA_POINTERS && vk_frame->img[i]; i++) num_imgs++; + for (int i = 0; i < AV_NUM_DATA_POINTERS && vk_frame->img[i]; i++) { + num_imgs++; + } if (num_imgs == 1) { // Single multiplane image — create plane views @@ -563,21 +611,19 @@ namespace vk { VkDescriptorImageInfo cursor_info = {compute.sampler, cursor.view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL}; std::array writes = {}; - writes[0] = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr, compute.desc_set, 0, 0, 1, - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &src_info, nullptr, nullptr}; - writes[1] = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr, compute.desc_set, 1, 0, 1, - VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &y_info, nullptr, nullptr}; - writes[2] = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr, compute.desc_set, 2, 0, 1, - VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &uv_info, nullptr, nullptr}; - writes[3] = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr, compute.desc_set, 3, 0, 1, - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &cursor_info, nullptr, nullptr}; + writes[0] = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr, compute.desc_set, 0, 0, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &src_info, nullptr, nullptr}; + writes[1] = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr, compute.desc_set, 1, 0, 1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &y_info, nullptr, nullptr}; + writes[2] = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr, compute.desc_set, 2, 0, 1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &uv_info, nullptr, nullptr}; + writes[3] = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr, compute.desc_set, 3, 0, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &cursor_info, nullptr, nullptr}; vkUpdateDescriptorSets(vk_dev.dev, writes.size(), writes.data(), 0, nullptr); } int dispatch_compute() { auto *vk_frame = (AVVkFrame *) frame->data[0]; int num_imgs = 0; - for (int i = 0; i < AV_NUM_DATA_POINTERS && vk_frame->img[i]; i++) num_imgs++; + for (int i = 0; i < AV_NUM_DATA_POINTERS && vk_frame->img[i]; i++) { + num_imgs++; + } // Rotate to next command buffer. With CMD_RING_SIZE slots, the buffer // we're about to reuse was submitted CMD_RING_SIZE frames ago. @@ -601,9 +647,7 @@ namespace vk { src_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL; src_barrier.dstQueueFamilyIndex = vk_dev.compute_qf; - vkCmdPipelineBarrier(cmd_buf, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, - 0, 0, nullptr, 0, nullptr, 1, &src_barrier); + vkCmdPipelineBarrier(cmd_buf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &src_barrier); // Transition cursor image if needed if (cursor.needs_transition) { @@ -616,9 +660,7 @@ namespace vk { cursor_barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; cursor_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; cursor_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - vkCmdPipelineBarrier(cmd_buf, - VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, - 0, 0, nullptr, 0, nullptr, 1, &cursor_barrier); + vkCmdPipelineBarrier(cmd_buf, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &cursor_barrier); cursor.needs_transition = false; } @@ -637,16 +679,12 @@ namespace vk { dst_barriers[i].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; } - vkCmdPipelineBarrier(cmd_buf, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, - 0, 0, nullptr, 0, nullptr, num_dst_barriers, dst_barriers.data()); + vkCmdPipelineBarrier(cmd_buf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, num_dst_barriers, dst_barriers.data()); // Bind pipeline and dispatch vkCmdBindPipeline(cmd_buf, VK_PIPELINE_BIND_POINT_COMPUTE, compute.pipeline); - vkCmdBindDescriptorSets(cmd_buf, VK_PIPELINE_BIND_POINT_COMPUTE, - compute.pipeline_layout, 0, 1, &compute.desc_set, 0, nullptr); - vkCmdPushConstants(cmd_buf, compute.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, - 0, sizeof(PushConstants), &push); + vkCmdBindDescriptorSets(cmd_buf, VK_PIPELINE_BIND_POINT_COMPUTE, compute.pipeline_layout, 0, 1, &compute.desc_set, 0, nullptr); + vkCmdPushConstants(cmd_buf, compute.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(PushConstants), &push); uint32_t gx = (frame->width + 15) / 16; uint32_t gy = (frame->height + 15) / 16; @@ -691,12 +729,16 @@ namespace vk { // Lock the queue (FFmpeg requires this) vk_dev.ctx->lock_queue( - (AVHWDeviceContext *)((AVHWFramesContext *)hw_frames_ctx->data)->device_ref->data, - vk_dev.compute_qf, 0); + (AVHWDeviceContext *) ((AVHWFramesContext *) hw_frames_ctx->data)->device_ref->data, + vk_dev.compute_qf, + 0 + ); auto res = vkQueueSubmit(vk_dev.compute_queue, 1, &submit, VK_NULL_HANDLE); vk_dev.ctx->unlock_queue( - (AVHWDeviceContext *)((AVHWFramesContext *)hw_frames_ctx->data)->device_ref->data, - vk_dev.compute_qf, 0); + (AVHWDeviceContext *) ((AVHWFramesContext *) hw_frames_ctx->data)->device_ref->data, + vk_dev.compute_qf, + 0 + ); if (res != VK_SUCCESS) { BOOST_LOG(error) << "vkQueueSubmit failed: " << res; @@ -718,12 +760,15 @@ namespace vk { VkPhysicalDeviceMemoryProperties mem_props; vkGetPhysicalDeviceMemoryProperties(vk_dev.phys_dev, &mem_props); for (uint32_t i = 0; i < mem_props.memoryTypeCount; i++) { - if ((type_bits & (1 << i)) && (mem_props.memoryTypes[i].propertyFlags & props) == props) + if ((type_bits & (1 << i)) && (mem_props.memoryTypes[i].propertyFlags & props) == props) { return i; + } } // Fallback: any matching type bit for (uint32_t i = 0; i < mem_props.memoryTypeCount; i++) { - if (type_bits & (1 << i)) return i; + if (type_bits & (1 << i)) { + return i; + } } return 0; } @@ -733,9 +778,15 @@ namespace vk { // Defer destruction — the GPU may still be using this image. // By the time we wrap around (4 frames later), it's guaranteed done. auto &slot = defer_ring[defer_idx]; - if (slot.view) vkDestroyImageView(vk_dev.dev, slot.view, nullptr); - if (slot.image) vkDestroyImage(vk_dev.dev, slot.image, nullptr); - if (slot.mem) vkFreeMemory(vk_dev.dev, slot.mem, nullptr); + if (slot.view) { + vkDestroyImageView(vk_dev.dev, slot.view, nullptr); + } + if (slot.image) { + vkDestroyImage(vk_dev.dev, slot.image, nullptr); + } + if (slot.mem) { + vkFreeMemory(vk_dev.dev, slot.mem, nullptr); + } slot = src; defer_idx = (defer_idx + 1) % DEFER_RING_SIZE; } @@ -743,26 +794,52 @@ namespace vk { } void cleanup_pipeline() { - if (!vk_dev.dev) return; + if (!vk_dev.dev) { + return; + } vkDeviceWaitIdle(vk_dev.dev); destroy_src_image(); // Flush deferred destroys for (auto &slot : defer_ring) { - if (slot.view) vkDestroyImageView(vk_dev.dev, slot.view, nullptr); - if (slot.image) vkDestroyImage(vk_dev.dev, slot.image, nullptr); - if (slot.mem) vkFreeMemory(vk_dev.dev, slot.mem, nullptr); + if (slot.view) { + vkDestroyImageView(vk_dev.dev, slot.view, nullptr); + } + if (slot.image) { + vkDestroyImage(vk_dev.dev, slot.image, nullptr); + } + if (slot.mem) { + vkFreeMemory(vk_dev.dev, slot.mem, nullptr); + } slot = {}; } - if (target.y_view) vkDestroyImageView(vk_dev.dev, target.y_view, nullptr); - if (target.uv_view) vkDestroyImageView(vk_dev.dev, target.uv_view, nullptr); + if (target.y_view) { + vkDestroyImageView(vk_dev.dev, target.y_view, nullptr); + } + if (target.uv_view) { + vkDestroyImageView(vk_dev.dev, target.uv_view, nullptr); + } destroy_cursor_image(); - if (cmd.pool) vkDestroyCommandPool(vk_dev.dev, cmd.pool, nullptr); - if (compute.sampler) vkDestroySampler(vk_dev.dev, compute.sampler, nullptr); - if (compute.desc_pool) vkDestroyDescriptorPool(vk_dev.dev, compute.desc_pool, nullptr); - if (compute.pipeline) vkDestroyPipeline(vk_dev.dev, compute.pipeline, nullptr); - if (compute.pipeline_layout) vkDestroyPipelineLayout(vk_dev.dev, compute.pipeline_layout, nullptr); - if (compute.ds_layout) vkDestroyDescriptorSetLayout(vk_dev.dev, compute.ds_layout, nullptr); - if (compute.shader_module) vkDestroyShaderModule(vk_dev.dev, compute.shader_module, nullptr); + if (cmd.pool) { + vkDestroyCommandPool(vk_dev.dev, cmd.pool, nullptr); + } + if (compute.sampler) { + vkDestroySampler(vk_dev.dev, compute.sampler, nullptr); + } + if (compute.desc_pool) { + vkDestroyDescriptorPool(vk_dev.dev, compute.desc_pool, nullptr); + } + if (compute.pipeline) { + vkDestroyPipeline(vk_dev.dev, compute.pipeline, nullptr); + } + if (compute.pipeline_layout) { + vkDestroyPipelineLayout(vk_dev.dev, compute.pipeline_layout, nullptr); + } + if (compute.ds_layout) { + vkDestroyDescriptorSetLayout(vk_dev.dev, compute.ds_layout, nullptr); + } + if (compute.shader_module) { + vkDestroyShaderModule(vk_dev.dev, compute.shader_module, nullptr); + } } static int init_hw_device(platf::avcodec_encode_device_t *, AVBufferRef **hw_device_buf) { @@ -788,6 +865,7 @@ namespace vk { VkQueue compute_queue = VK_NULL_HANDLE; PFN_vkGetMemoryFdPropertiesKHR getMemoryFdProperties = nullptr; }; + vk_device_t vk_dev = {}; // Compute pipeline @@ -800,16 +878,19 @@ namespace vk { VkDescriptorSet desc_set = VK_NULL_HANDLE; VkSampler sampler = VK_NULL_HANDLE; }; + compute_pipeline_t compute = {}; // Command submission — ring of buffers to avoid reuse while in-flight. // No CPU waits: by the time we wrap around, the old submission is long done. static constexpr int CMD_RING_SIZE = 3; + struct cmd_submission_t { VkCommandPool pool = VK_NULL_HANDLE; std::array ring = {}; int ring_idx = 0; }; + cmd_submission_t cmd = {}; // Source DMA-BUF image with deferred destruction @@ -818,6 +899,7 @@ namespace vk { VkDeviceMemory mem = VK_NULL_HANDLE; VkImageView view = VK_NULL_HANDLE; }; + src_image_t src = {}; static constexpr int DEFER_RING_SIZE = 4; std::array defer_ring = {}; @@ -830,6 +912,7 @@ namespace vk { bool views_created = false; bool initialized = false; }; + target_state_t target = {}; bool descriptors_dirty = false; @@ -841,6 +924,7 @@ namespace vk { VkImageView view = VK_NULL_HANDLE; bool needs_transition = false; } cursor = {}; + unsigned long cursor_serial = 0; // Push constants (color matrix) @@ -854,18 +938,22 @@ namespace vk { } bool validate() { - if (!avcodec_find_encoder_by_name("h264_vulkan") && !avcodec_find_encoder_by_name("hevc_vulkan")) + if (!avcodec_find_encoder_by_name("h264_vulkan") && !avcodec_find_encoder_by_name("hevc_vulkan")) { return false; + } AVBufferRef *dev = nullptr; - if (create_vulkan_hwdevice(&dev) < 0) + if (create_vulkan_hwdevice(&dev) < 0) { return false; + } av_buffer_unref(&dev); return true; } std::unique_ptr make_avcodec_encode_device_vram(int w, int h, int offset_x, int offset_y) { auto dev = std::make_unique(); - if (dev->init(w, h, offset_x, offset_y) < 0) return nullptr; + if (dev->init(w, h, offset_x, offset_y) < 0) { + return nullptr; + } return dev; } diff --git a/src/video.cpp b/src/video.cpp index d277691c902..2f30c4ab510 100644 --- a/src/video.cpp +++ b/src/video.cpp @@ -3026,7 +3026,7 @@ namespace video { // Try render device path first (like VAAPI does), then fallback to device indices auto render_device = config::video.adapter_name.empty() ? "/dev/dri/renderD128" : config::video.adapter_name.c_str(); - + auto status = av_hwdevice_ctx_create(&hw_device_buf, AV_HWDEVICE_TYPE_VULKAN, render_device, nullptr, 0); if (status >= 0) { BOOST_LOG(info) << "Using Vulkan device: "sv << render_device; diff --git a/tests/integration/test_config_consistency.cpp b/tests/integration/test_config_consistency.cpp index 01e349b0c6d..821c5923df7 100644 --- a/tests/integration/test_config_consistency.cpp +++ b/tests/integration/test_config_consistency.cpp @@ -36,6 +36,7 @@ class ConfigConsistencyTest: public ::testing::Test { {"AMD AMF Encoder", "amd"}, {"VideoToolbox Encoder", "vt"}, {"VA-API Encoder", "vaapi"}, + {"Vulkan Encoder", "vulkan"}, {"Software Encoder", "sw"} }; } From 0c115e70e63bca86a4c33cfa5a10133369fdb828 Mon Sep 17 00:00:00 2001 From: neatnoise Date: Wed, 18 Mar 2026 10:24:49 +0100 Subject: [PATCH 20/29] Sort vk_rc keys alphabetically and reorder vulkan/vaapi sections --- src_assets/common/assets/web/config.html | 14 +++++++------- .../common/assets/web/public/assets/locale/en.json | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src_assets/common/assets/web/config.html b/src_assets/common/assets/web/config.html index c4de821642a..b90a62145e3 100644 --- a/src_assets/common/assets/web/config.html +++ b/src_assets/common/assets/web/config.html @@ -326,18 +326,18 @@

{{ $t('config.configuration') }}

}, }, { - id: "vulkan", - name: "Vulkan Encoder", + id: "vaapi", + name: "VA-API Encoder", options: { - "vk_tune": 2, - "vk_rc_mode": 4, + "vaapi_strict_rc_buffer": "disabled", }, }, { - id: "vaapi", - name: "VA-API Encoder", + id: "vulkan", + name: "Vulkan Encoder", options: { - "vaapi_strict_rc_buffer": "disabled", + "vk_tune": 2, + "vk_rc_mode": 4, }, }, { diff --git a/src_assets/common/assets/web/public/assets/locale/en.json b/src_assets/common/assets/web/public/assets/locale/en.json index 05e38d05aa5..d3a878e0c79 100644 --- a/src_assets/common/assets/web/public/assets/locale/en.json +++ b/src_assets/common/assets/web/public/assets/locale/en.json @@ -383,10 +383,10 @@ "vk_tune_hq": "High Quality (hq)", "vk_tune_ll": "Low Latency (ll)", "vk_tune_ull": "Ultra Low Latency (ull)", + "vk_rc_cbr": "CBR (Constant Bitrate)", + "vk_rc_cqp": "CQP (Constant QP)", "vk_rc_mode": "Rate Control", "vk_rc_mode_desc": "Rate control mode for encoding. Auto lets the driver decide.", - "vk_rc_cqp": "CQP (Constant QP)", - "vk_rc_cbr": "CBR (Constant Bitrate)", "vk_rc_vbr": "VBR (Variable Bitrate)", "virtual_sink": "Virtual Sink", "virtual_sink_desc": "Manually specify a virtual audio device to use. If unset, the device is chosen automatically. We strongly recommend leaving this field blank to use automatic device selection!", From f6f97020d4af1180a4546b342cb152c7ad3d3b6f Mon Sep 17 00:00:00 2001 From: neatnoise Date: Wed, 18 Mar 2026 10:41:41 +0100 Subject: [PATCH 21/29] Fix y_invert handling for Vulkan encoder with wlroots GLES2 capture Sway's GLES2 renderer exports framebuffers in OpenGL's bottom-up convention and signals this via the Y_INVERT flag. The wlroots capture stored this flag but never passed it to the Vulkan encoder, resulting in a mangled picture. Propagate y_invert through img_descriptor_t to the Vulkan compute shader, which now flips the source texture Y coordinate when set. --- src/platform/linux/graphics.h | 3 + src/platform/linux/shaders/rgb2yuv.comp | 5 + src/platform/linux/shaders/rgb2yuv.spv | Bin 7440 -> 7820 bytes src/platform/linux/shaders/rgb2yuv.spv.h | 462 ++++++++++++----------- src/platform/linux/vulkan_encode.cpp | 2 + src/platform/linux/wayland.h | 2 +- src/platform/linux/wlgrab.cpp | 1 + 7 files changed, 249 insertions(+), 226 deletions(-) diff --git a/src/platform/linux/graphics.h b/src/platform/linux/graphics.h index 9a62dfce1f5..286a700bf25 100644 --- a/src/platform/linux/graphics.h +++ b/src/platform/linux/graphics.h @@ -305,6 +305,9 @@ namespace egl { // Increment sequence when new rgb_t needs to be created std::uint64_t sequence; + // Frame is vertically flipped (GL convention) + bool y_invert {false}; + // PipeWire metadata std::optional pts; std::optional seq; diff --git a/src/platform/linux/shaders/rgb2yuv.comp b/src/platform/linux/shaders/rgb2yuv.comp index 2603909c000..f73bee0e69b 100644 --- a/src/platform/linux/shaders/rgb2yuv.comp +++ b/src/platform/linux/shaders/rgb2yuv.comp @@ -18,6 +18,7 @@ layout(push_constant) uniform PushConstants { ivec2 dst_size; ivec2 cursor_pos; ivec2 cursor_size; // w=0 means no cursor + int y_invert; } pc; vec3 blend_cursor(vec3 rgb, ivec2 pos) { @@ -38,6 +39,8 @@ void main() { vec2 scale = vec2(pc.src_size) / vec2(pc.dst_size); vec2 uv = (vec2(pc.src_offset) + (vec2(pos) + 0.5) * scale) * inv_tex; + if (pc.y_invert != 0) + uv.y = 1.0 - uv.y; vec3 rgb = texture(rgb_in, uv).rgb; if (pc.cursor_size.x > 0) @@ -50,6 +53,8 @@ void main() { // UV plane (half resolution, one thread per 2x2 block) if ((pos.x & 1) == 0 && (pos.y & 1) == 0) { vec2 step = scale * inv_tex; + if (pc.y_invert != 0) + step.y = -step.y; vec3 rgb_r = texture(rgb_in, uv + vec2(step.x, 0)).rgb; vec3 rgb_b = texture(rgb_in, uv + vec2(0, step.y)).rgb; diff --git a/src/platform/linux/shaders/rgb2yuv.spv b/src/platform/linux/shaders/rgb2yuv.spv index 1e249160d3290265f4a204882c778d573d85800d..6a76223f44db060f0feb95454168a90a5e166b8b 100644 GIT binary patch literal 7820 zcmZvf3y{}U6~}+N~KzsP$VI)#n zfLgv9D@z2e47D;5XQ(vGS1+xxf~>LBo@!)`Q=iXo?-zgVcxTU?@A;l{&pp3;@A>`q z-`X;fI&jV)C@Mpi8_Ri!?%=&9)8)sUK>b;`R=>0Y*cVfRsQne2ppt5#L* z+mD#Nz=M$`eP^E|--nEVmm67Q?f&>#%pC)E>64i$c1-M7dpPTnb6(<{BiGsBtVGVj z66d;dK0`Qbl$+Mzh7|7P2FK>qalH-hHHAB^!3{0k{029yaA%=s@$@s%6A){ReGu58 z?LG}h4k-48XyYCFwO@&Et+r#2Ek3cagBo@-_E;Q=6&u@9Vzpn19bENdTZi$Zh%#;h zRa>`se~^3CiL_Ifd!(&@47PjGiIArDyAN{CHGUM@c+W+9bg}i1;~shkjEU%1%rj8> z*BVSs{cAY)IC5&Y7w(PN#&sZ`T_?8BCTG6URCXZR+Q*?g5r^}%$JbWB?HuooBmOS1 z&zg0-d#P(m!P;YCr=xv#)FK_IE=H-6HAbs&!z1>a=4zk-d5C|$7ii6*w&X?>^DdJ)3EIYZTEUM_6YPOvUx7{ zqnzShb8Y)!JxSerCENx$?}KtQajt7_htK;j825fR)*SLV{sSJ5o{Ozt{WfN~_8CYY zGMf`$fL>TQd50-3BGx@S6VX416+FYmg+o<6Jd3?>Hez3Thg{QjjD0_%@9WI97e9bF zUw#uYavwzGt-b!Rfd7q8ehDIH{o>Sc9@x69Gc|k&oEqHE)UXt+FEuO!J74}K@+QCf zMfSs*mLt~Wo*D1j)^`EgVSUD&kH}e{*nIB4w!AgWKwpH|KMS#^qc1MpV)n&7zNByy z(dQE5Jy=orwZv$zLcAODJ#fD3K92azmm;oZt~H2!@_eFjnR6L-_9=7L!pUdO~IyPoB?!ja z?u#`|L0^kllkXmD@(x~y$ZsLWv%S7>?zLz71+>F6)pr9T=NXE~}x+ zMX-H(BQlpL&*=!BMLx0KiR4pz$Ba9bIAgpg&T%bk_P*SNcwbHw#nmEVHd zeD&JUHzWELhxHkgzSsnIPbMSH-n<1{-)%gL`?494%f8$ScDOJ4wjgrui#Ye-JuGPc z4kY*By>RlY$vq7Ibg<_xpB|nMmUpB#`>^Fx!=mE127L<oPW6na(L0ngSd)c!kVC!|?>UT+rF*a+Q3pR)A8t?r2 zU4nMFhB4rPzP$A%zdH4O80`AiY`kk* z-#WCz`i%JqB4>T#+|`eQXA+klzYyDc)4LagfyfH&zBWnE4UZNURnz$AKAO~*yV8iRo#gFW^QBM)9i`b zJvGl97BtR%cCPznZ2Cu?*tsRvcZ2iH<34T0z5{WeyuqzmMqi zeXaci#C-CZdp|gHyTGaA0kFQ*@k6ll<$Kv-_u)ZA-gjZ-3~Ia&+jour`&oM^`e9@- z@({8a&iCCTh`f92eSZw?@V@JN6p{13i_?!k1)JY}PX3>P<(v6`jxBF~&px@->Ahco zUCaAmyz5xY6KIFE81pzHXD#A<1D^!1LslWq+l6*G&u`gIM9z8Q-2JD(&h;5q5bOE; z9+A&?>=^EgT;hC&xhaE1YM)8RrmeInQ3a zlD!=UKMd^s^|w$D+*t5>a67sKanFp~04JYs_(rgE<@4dIK>x$pH z^nDJIvo3LRT>~~3e|vIWiy?0=?_cJr(?i#T&FeE7Z%)_!GTKr10{8|*&UMAN^X$F{ zz67@3e8Ur?&Kfs?UB`8ecfMeeAn2C&Kk!23XyXSah~l-aGovw@oTu;uV#Pz z23}w4`z_e{@}6b#t5e@Dui*b`Hn*|vY4${&{#e9<#<|bVb-&Ud9bo&T9i9Go87#j6$+`a*EbmBv_#pD>kG*^_ zhWAw8AVkhH5+_$H*j%PduEB8f>5t4)=WYxEo7ZPE-kjczedHOgYfKv==epwDzrDfM zoBl|QI&16;HizpP?|j!7gU%Yp?1#v?hB(hQ5}apCf4mkh_p8|-qu}+WzR_Uk%X^l| zuTFjYgI(X6jdyM9I~<+*jA=*YtWTW&=m0nS<8|29oBlWeTdvt32V$rG^v5_j`Sizl zuw4416KpQ|^v49S>+9q1|NbvL7(&0I&%5DpU;Ta@T71p^=z^1vq(2UWbAC6{0x-9+ z?rHW!o&Hz~HqL!^uKQ(d8(e*d(24zQiQPqR=QZLmYMY-7S51SfCKa0g?{Tf-G)?xEQ7haf$0Tgi7A*z@u?j^{NBeK?$a{ttfxSWa=M zNL%H%=p+bZ%%9(YZvrRpJYvo5*>uC}vrg?Jz|NOXO-F*AI|ZGZ-VBycO-F&{6o;x= z)6o#dG;4Y*cJelBnhLKkH5~(XzP#)E`}jEUvB(bU_W$VP!FdOKMmdd%{(1j zUw$*s0Q=lE&o21e{Y31{P2ameGvW26wv)ilmruTTfUVhli8~c6Z(M#`zZ2|yeg4i; c{B7;C`8@i)%lS>J)}90J-B!QMPESSt2RCf@KmY&$ literal 7440 zcmZvfd$5*O6~O%s7<;2TD;9Nq>eG{*ut(LZ zs(pJBGZ5T{EbTdMnS2kj7rfla8f*8)&t~puu%(Y?rr6QhtNJ+mk#k<+oFmuK;Os=s z#u8^;IoA-*9_2pQ;06`$=my8;)N$Pn?n8w;slg2?+F<{&pY+b2UpdqY3a{1>PY+=uzkk966`&*{wB10 z<8#)&tJuc7Ut7^1v|sk)aL!M9VI6A^+TI06YTgTW&9S$GUE_gt;u&}yk?U-5yNfNK zxHcwfE9SDdy-ifDnws3>vF$Itc()w!AB63>*LH7@z}^deAlZBl-aR?Rvt@11{xXuf z*GjnMa6W(KGsIcf+>Tb{O&It34Xml;bG!rgOi#nsuRfAl)?SG8Aai)a3($)SC+{%D z1;n~%ry%-Ipn}hEap6$abk^e8KMnC7dSN^xef=@7@`R^W}d?jNF-syuH^i z4Dj3dEu4JjTmhC#?R8-D$S2P?!RGOv zC(l)2`Q*78EEoG4u+MFES<`i3InVc{g}VV;-kOQK5o|7fiMt6b@4jT8Zw9;1C-EHH z(YGLS#!{m4J97?ihr#Gu5&epT$5zMWJl%%v`X(dIGkrU@z8}%AXJtJi=d<&SY(zUe zBkR!{5IN6;IQw@D1*!_~v**^{}@5q@x9$P*=oLKz!pl=Q$ zXAk1!Ist4hK7F~qs2?$x=Q;D#xgTEwn|A{-#+%c%e+BKZt}$~FIqQnIls)@0*nZtN zYa~XU8eavQ!@9;h-x>?i4r>^5G9qUUan?2uoVDed&WFo0ZGK1e!0StY3&75ox4-09 zr@uvD>)W&O*0#T|qtl-;ryz3nC(cIsJ_M0<*I#|xTku!4!cKXkmITKDk zd6t6Za(9=3%_X0Eu^eoDef{sn*>L(5eW-f4uf7LY6kjX28^*hIE}VR1c)4Te!SSiO z5bvA0jdf46Cu;Z9Jcm)xIQQAP?w7F};oLuUVyBc?zh|9i9`|Vz_GZL=@(jCAeiz(< z$mjmwSvYwI)9dwKU)K3!Y-6nB`SCZ)-AMAz1)JMF*;0HyJMDWA=gS+j75!6W8|D6S3c+O zVz9g;@69#X@||$@wYK;@Kl&~~u&(jWx5iCqhc%437Ll`tIBUBeoVDe> zc>|n#J{g&WxbJ>H+z78P{e2tke0ldE`PJ#~J7DYEv+>rpzdO+m`!nWdM9%)ixgXyJ z&mu1GyIZmCH|O+ruw3)KxgInFJsH+e*C-mJ*WC!LF9Z!;^g`#*j#-2a{UWKKKCQ@)Hxfkg3asNj5nue z<88FVy2iYQ$XQpM^Y<3mesez(qfU)?z~->7@y@qKiw~{TFy_CAoHfK*+q>YbE%)Pp za5-Pi`@z&oU-}z>?R??U_?W^QBM)9i^l_oEwZocrut_siJ)CQ~PNX^HjswDX#ImSETS z4ByOtzIoWbqnzja%6aa&@2?Rw>;Eic!tDtsZ_aQdvE}XIsxr47TYhh3I@~7mjRyO? zwj(|-|M!f6lh5z)v0ypHp(1US|9|5kj4^-ycYRon81pv&|LqH}&pv%t`+=P=pPnXw zojV?#o;twt>1iTZPI0K3J#|7D)9mS^*vZ@M>0|Kv($mMm&X>3TR&sv=JPFxO-~Nt1 z0G#i_tho!${0E^Ypq=X)560G)|EZI~u3J8H4*_Rx?!9vlh1ZwfJ_&ZdeDWOzwrBGt q?z3Qd #include -static const std::array rgb2yuv_comp_spv = { - 0x07230203, 0x00010000, 0x000d000b, 0x00000270, 0x00000000, 0x00020011, 0x00000001, 0x00020011, +static const std::array rgb2yuv_comp_spv = { + 0x07230203, 0x00010000, 0x000d000b, 0x00000293, 0x00000000, 0x00020011, 0x00000001, 0x00020011, 0x00000032, 0x00020011, 0x00000038, 0x0006000b, 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, 0x00000000, 0x0003000e, 0x00000000, 0x00000001, 0x0006000f, 0x00000005, 0x00000004, 0x6e69616d, 0x00000000, 0x00000061, 0x00060010, 0x00000004, 0x00000011, 0x00000010, 0x00000010, 0x00000001, @@ -18,228 +18,240 @@ static const std::array rgb2yuv_comp_spv = { 0x00000015, 0x00000004, 0x00000023, 0x00000038, 0x00050048, 0x00000015, 0x00000005, 0x00000023, 0x00000040, 0x00050048, 0x00000015, 0x00000006, 0x00000023, 0x00000048, 0x00050048, 0x00000015, 0x00000007, 0x00000023, 0x00000050, 0x00050048, 0x00000015, 0x00000008, 0x00000023, 0x00000058, - 0x00050048, 0x00000015, 0x00000009, 0x00000023, 0x00000060, 0x00040047, 0x00000045, 0x00000021, - 0x00000003, 0x00040047, 0x00000045, 0x00000022, 0x00000000, 0x00040047, 0x00000061, 0x0000000b, - 0x0000001c, 0x00040047, 0x0000007b, 0x00000021, 0x00000000, 0x00040047, 0x0000007b, 0x00000022, - 0x00000000, 0x00030047, 0x000000b5, 0x00000019, 0x00040047, 0x000000b5, 0x00000021, 0x00000001, - 0x00040047, 0x000000b5, 0x00000022, 0x00000000, 0x00030047, 0x00000127, 0x00000019, 0x00040047, - 0x00000127, 0x00000021, 0x00000002, 0x00040047, 0x00000127, 0x00000022, 0x00000000, 0x00040047, - 0x0000013d, 0x0000000b, 0x00000019, 0x00020013, 0x00000002, 0x00030021, 0x00000003, 0x00000002, - 0x00030016, 0x00000006, 0x00000020, 0x00040017, 0x00000007, 0x00000006, 0x00000003, 0x00040015, - 0x00000009, 0x00000020, 0x00000001, 0x00040017, 0x0000000a, 0x00000009, 0x00000002, 0x00040017, - 0x00000013, 0x00000006, 0x00000004, 0x00040017, 0x00000014, 0x00000006, 0x00000002, 0x000c001e, - 0x00000015, 0x00000013, 0x00000013, 0x00000013, 0x00000014, 0x00000014, 0x0000000a, 0x0000000a, - 0x0000000a, 0x0000000a, 0x0000000a, 0x00040020, 0x00000016, 0x00000009, 0x00000015, 0x0004003b, - 0x00000016, 0x00000017, 0x00000009, 0x0004002b, 0x00000009, 0x00000018, 0x00000008, 0x00040020, - 0x00000019, 0x00000009, 0x0000000a, 0x00020014, 0x0000001d, 0x00040015, 0x0000001e, 0x00000020, - 0x00000000, 0x0004002b, 0x0000001e, 0x0000001f, 0x00000000, 0x0004002b, 0x00000009, 0x00000023, - 0x00000000, 0x0004002b, 0x0000001e, 0x00000027, 0x00000001, 0x0004002b, 0x00000009, 0x00000030, - 0x00000009, 0x00040020, 0x00000031, 0x00000009, 0x00000009, 0x00090019, 0x00000042, 0x00000006, - 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x0003001b, 0x00000043, - 0x00000042, 0x00040020, 0x00000044, 0x00000000, 0x00000043, 0x0004003b, 0x00000044, 0x00000045, - 0x00000000, 0x0004002b, 0x00000006, 0x00000049, 0x3f000000, 0x0004002b, 0x00000006, 0x00000050, - 0x00000000, 0x0004002b, 0x0000001e, 0x00000055, 0x00000003, 0x00040017, 0x0000005f, 0x0000001e, - 0x00000003, 0x00040020, 0x00000060, 0x00000001, 0x0000005f, 0x0004003b, 0x00000060, 0x00000061, - 0x00000001, 0x00040017, 0x00000062, 0x0000001e, 0x00000002, 0x0004002b, 0x00000009, 0x00000068, - 0x00000007, 0x0004002b, 0x00000006, 0x0000007a, 0x3f800000, 0x0004003b, 0x00000044, 0x0000007b, - 0x00000000, 0x0004002b, 0x00000009, 0x00000083, 0x00000006, 0x0004002b, 0x00000009, 0x0000008c, - 0x00000005, 0x00040020, 0x000000a9, 0x00000009, 0x00000013, 0x00040020, 0x000000af, 0x00000009, - 0x00000006, 0x00090019, 0x000000b3, 0x00000006, 0x00000001, 0x00000000, 0x00000000, 0x00000000, - 0x00000002, 0x00000000, 0x00040020, 0x000000b4, 0x00000000, 0x000000b3, 0x0004003b, 0x000000b4, - 0x000000b5, 0x00000000, 0x0004002b, 0x00000009, 0x000000b9, 0x00000003, 0x0004002b, 0x00000009, - 0x000000c3, 0x00000001, 0x0005002c, 0x0000000a, 0x000000f6, 0x000000c3, 0x00000023, 0x0005002c, - 0x0000000a, 0x000000fd, 0x00000023, 0x000000c3, 0x0005002c, 0x0000000a, 0x00000104, 0x000000c3, - 0x000000c3, 0x0004002b, 0x00000006, 0x00000112, 0x3e800000, 0x0004002b, 0x00000009, 0x0000011e, - 0x00000002, 0x0004003b, 0x000000b4, 0x00000127, 0x00000000, 0x0004002b, 0x00000009, 0x0000012d, - 0x00000004, 0x0004002b, 0x0000001e, 0x0000013c, 0x00000010, 0x0006002c, 0x0000005f, 0x0000013d, - 0x0000013c, 0x0000013c, 0x00000027, 0x0005002c, 0x00000014, 0x0000026e, 0x0000007a, 0x0000007a, - 0x0005002c, 0x00000014, 0x0000026f, 0x00000049, 0x00000049, 0x00050036, 0x00000002, 0x00000004, - 0x00000000, 0x00000003, 0x000200f8, 0x00000005, 0x000300f7, 0x0000013e, 0x00000000, 0x000300fb, - 0x0000001f, 0x0000013f, 0x000200f8, 0x0000013f, 0x0004003d, 0x0000005f, 0x00000063, 0x00000061, - 0x0007004f, 0x00000062, 0x00000064, 0x00000063, 0x00000063, 0x00000000, 0x00000001, 0x0004007c, - 0x0000000a, 0x00000065, 0x00000064, 0x00050051, 0x00000009, 0x00000067, 0x00000065, 0x00000000, - 0x00060041, 0x00000031, 0x00000069, 0x00000017, 0x00000068, 0x0000001f, 0x0004003d, 0x00000009, - 0x0000006a, 0x00000069, 0x000500af, 0x0000001d, 0x0000006b, 0x00000067, 0x0000006a, 0x000400a8, - 0x0000001d, 0x0000006c, 0x0000006b, 0x000300f7, 0x0000006e, 0x00000000, 0x000400fa, 0x0000006c, - 0x0000006d, 0x0000006e, 0x000200f8, 0x0000006d, 0x00050051, 0x00000009, 0x00000070, 0x00000065, - 0x00000001, 0x00060041, 0x00000031, 0x00000071, 0x00000017, 0x00000068, 0x00000027, 0x0004003d, - 0x00000009, 0x00000072, 0x00000071, 0x000500af, 0x0000001d, 0x00000073, 0x00000070, 0x00000072, - 0x000200f9, 0x0000006e, 0x000200f8, 0x0000006e, 0x000700f5, 0x0000001d, 0x00000074, 0x0000006b, - 0x0000013f, 0x00000073, 0x0000006d, 0x000300f7, 0x00000076, 0x00000000, 0x000400fa, 0x00000074, - 0x00000075, 0x00000076, 0x000200f8, 0x00000075, 0x000200f9, 0x0000013e, 0x000200f8, 0x00000076, - 0x0004003d, 0x00000043, 0x0000007c, 0x0000007b, 0x00040064, 0x00000042, 0x0000007d, 0x0000007c, - 0x00050067, 0x0000000a, 0x0000007e, 0x0000007d, 0x00000023, 0x0004006f, 0x00000014, 0x0000007f, - 0x0000007e, 0x00050088, 0x00000014, 0x00000081, 0x0000026e, 0x0000007f, 0x00050041, 0x00000019, - 0x00000084, 0x00000017, 0x00000083, 0x0004003d, 0x0000000a, 0x00000085, 0x00000084, 0x0004006f, - 0x00000014, 0x00000086, 0x00000085, 0x00050041, 0x00000019, 0x00000087, 0x00000017, 0x00000068, - 0x0004003d, 0x0000000a, 0x00000088, 0x00000087, 0x0004006f, 0x00000014, 0x00000089, 0x00000088, - 0x00050088, 0x00000014, 0x0000008a, 0x00000086, 0x00000089, 0x00050041, 0x00000019, 0x0000008d, - 0x00000017, 0x0000008c, 0x0004003d, 0x0000000a, 0x0000008e, 0x0000008d, 0x0004006f, 0x00000014, - 0x0000008f, 0x0000008e, 0x0004006f, 0x00000014, 0x00000091, 0x00000065, 0x00050081, 0x00000014, - 0x00000093, 0x00000091, 0x0000026f, 0x00050085, 0x00000014, 0x00000095, 0x00000093, 0x0000008a, - 0x00050081, 0x00000014, 0x00000096, 0x0000008f, 0x00000095, 0x00050085, 0x00000014, 0x00000098, - 0x00000096, 0x00000081, 0x0004003d, 0x00000043, 0x0000009a, 0x0000007b, 0x00070058, 0x00000013, - 0x0000009c, 0x0000009a, 0x00000098, 0x00000002, 0x00000050, 0x0008004f, 0x00000007, 0x0000009d, - 0x0000009c, 0x0000009c, 0x00000000, 0x00000001, 0x00000002, 0x00060041, 0x00000031, 0x0000009e, - 0x00000017, 0x00000030, 0x0000001f, 0x0004003d, 0x00000009, 0x0000009f, 0x0000009e, 0x000500ad, - 0x0000001d, 0x000000a0, 0x0000009f, 0x00000023, 0x000300f7, 0x000000a2, 0x00000000, 0x000400fa, - 0x000000a0, 0x000000a1, 0x000000a2, 0x000200f8, 0x000000a1, 0x00050041, 0x00000019, 0x00000149, - 0x00000017, 0x00000018, 0x0004003d, 0x0000000a, 0x0000014a, 0x00000149, 0x00050082, 0x0000000a, - 0x0000014b, 0x00000065, 0x0000014a, 0x00050051, 0x00000009, 0x0000014d, 0x0000014b, 0x00000000, - 0x000500af, 0x0000001d, 0x0000014e, 0x0000014d, 0x00000023, 0x000300f7, 0x00000153, 0x00000000, - 0x000400fa, 0x0000014e, 0x0000014f, 0x00000153, 0x000200f8, 0x0000014f, 0x00050051, 0x00000009, - 0x00000151, 0x0000014b, 0x00000001, 0x000500af, 0x0000001d, 0x00000152, 0x00000151, 0x00000023, - 0x000200f9, 0x00000153, 0x000200f8, 0x00000153, 0x000700f5, 0x0000001d, 0x00000154, 0x0000014e, - 0x000000a1, 0x00000152, 0x0000014f, 0x000300f7, 0x0000015b, 0x00000000, 0x000400fa, 0x00000154, - 0x00000155, 0x0000015b, 0x000200f8, 0x00000155, 0x000500b1, 0x0000001d, 0x0000015a, 0x0000014d, - 0x0000009f, 0x000200f9, 0x0000015b, 0x000200f8, 0x0000015b, 0x000700f5, 0x0000001d, 0x0000015c, - 0x00000154, 0x00000153, 0x0000015a, 0x00000155, 0x000300f7, 0x00000163, 0x00000000, 0x000400fa, - 0x0000015c, 0x0000015d, 0x00000163, 0x000200f8, 0x0000015d, 0x00050051, 0x00000009, 0x0000015f, - 0x0000014b, 0x00000001, 0x00060041, 0x00000031, 0x00000160, 0x00000017, 0x00000030, 0x00000027, - 0x0004003d, 0x00000009, 0x00000161, 0x00000160, 0x000500b1, 0x0000001d, 0x00000162, 0x0000015f, - 0x00000161, 0x000200f9, 0x00000163, 0x000200f8, 0x00000163, 0x000700f5, 0x0000001d, 0x00000164, - 0x0000015c, 0x0000015b, 0x00000162, 0x0000015d, 0x000300f7, 0x00000177, 0x00000000, 0x000400fa, - 0x00000164, 0x00000165, 0x00000177, 0x000200f8, 0x00000165, 0x0004003d, 0x00000043, 0x00000166, - 0x00000045, 0x0004006f, 0x00000014, 0x00000168, 0x0000014b, 0x00050081, 0x00000014, 0x0000016a, - 0x00000168, 0x0000026f, 0x00050041, 0x00000019, 0x0000016b, 0x00000017, 0x00000030, 0x0004003d, - 0x0000000a, 0x0000016c, 0x0000016b, 0x0004006f, 0x00000014, 0x0000016d, 0x0000016c, 0x00050088, - 0x00000014, 0x0000016e, 0x0000016a, 0x0000016d, 0x00070058, 0x00000013, 0x0000016f, 0x00000166, - 0x0000016e, 0x00000002, 0x00000050, 0x0008004f, 0x00000007, 0x00000172, 0x0000016f, 0x0000016f, - 0x00000002, 0x00000001, 0x00000000, 0x00050051, 0x00000006, 0x00000174, 0x0000016f, 0x00000003, - 0x00060050, 0x00000007, 0x00000175, 0x00000174, 0x00000174, 0x00000174, 0x0008000c, 0x00000007, - 0x00000176, 0x00000001, 0x0000002e, 0x0000009d, 0x00000172, 0x00000175, 0x000200f9, 0x00000177, - 0x000200f8, 0x00000177, 0x000700f5, 0x00000007, 0x00000237, 0x0000009d, 0x00000163, 0x00000176, - 0x00000165, 0x000200f9, 0x000000a2, 0x000200f8, 0x000000a2, 0x000700f5, 0x00000007, 0x00000238, - 0x0000009d, 0x00000076, 0x00000237, 0x00000177, 0x00050041, 0x000000a9, 0x000000aa, 0x00000017, - 0x00000023, 0x0004003d, 0x00000013, 0x000000ab, 0x000000aa, 0x0008004f, 0x00000007, 0x000000ac, - 0x000000ab, 0x000000ab, 0x00000000, 0x00000001, 0x00000002, 0x00050094, 0x00000006, 0x000000ae, - 0x000000ac, 0x00000238, 0x00060041, 0x000000af, 0x000000b0, 0x00000017, 0x00000023, 0x00000055, - 0x0004003d, 0x00000006, 0x000000b1, 0x000000b0, 0x00050081, 0x00000006, 0x000000b2, 0x000000ae, - 0x000000b1, 0x0004003d, 0x000000b3, 0x000000b6, 0x000000b5, 0x00060041, 0x000000af, 0x000000ba, - 0x00000017, 0x000000b9, 0x0000001f, 0x0004003d, 0x00000006, 0x000000bb, 0x000000ba, 0x00050085, - 0x00000006, 0x000000bc, 0x000000b2, 0x000000bb, 0x00060041, 0x000000af, 0x000000bd, 0x00000017, - 0x000000b9, 0x00000027, 0x0004003d, 0x00000006, 0x000000be, 0x000000bd, 0x00050081, 0x00000006, - 0x000000bf, 0x000000bc, 0x000000be, 0x00070050, 0x00000013, 0x000000c0, 0x000000bf, 0x00000050, - 0x00000050, 0x00000050, 0x00040063, 0x000000b6, 0x00000065, 0x000000c0, 0x000500c7, 0x00000009, - 0x000000c4, 0x00000067, 0x000000c3, 0x000500aa, 0x0000001d, 0x000000c5, 0x000000c4, 0x00000023, - 0x000300f7, 0x000000c7, 0x00000000, 0x000400fa, 0x000000c5, 0x000000c6, 0x000000c7, 0x000200f8, - 0x000000c6, 0x00050051, 0x00000009, 0x000000c9, 0x00000065, 0x00000001, 0x000500c7, 0x00000009, - 0x000000ca, 0x000000c9, 0x000000c3, 0x000500aa, 0x0000001d, 0x000000cb, 0x000000ca, 0x00000023, - 0x000200f9, 0x000000c7, 0x000200f8, 0x000000c7, 0x000700f5, 0x0000001d, 0x000000cc, 0x000000c5, - 0x000000a2, 0x000000cb, 0x000000c6, 0x000300f7, 0x000000ce, 0x00000000, 0x000400fa, 0x000000cc, - 0x000000cd, 0x000000ce, 0x000200f8, 0x000000cd, 0x00050085, 0x00000014, 0x000000d2, 0x0000008a, - 0x00000081, 0x0004003d, 0x00000043, 0x000000d4, 0x0000007b, 0x00050051, 0x00000006, 0x000000d7, - 0x000000d2, 0x00000000, 0x00050050, 0x00000014, 0x000000d8, 0x000000d7, 0x00000050, 0x00050081, - 0x00000014, 0x000000d9, 0x00000098, 0x000000d8, 0x00070058, 0x00000013, 0x000000da, 0x000000d4, - 0x000000d9, 0x00000002, 0x00000050, 0x0008004f, 0x00000007, 0x000000db, 0x000000da, 0x000000da, - 0x00000000, 0x00000001, 0x00000002, 0x0004003d, 0x00000043, 0x000000dd, 0x0000007b, 0x00050051, - 0x00000006, 0x000000e0, 0x000000d2, 0x00000001, 0x00050050, 0x00000014, 0x000000e1, 0x00000050, - 0x000000e0, 0x00050081, 0x00000014, 0x000000e2, 0x00000098, 0x000000e1, 0x00070058, 0x00000013, - 0x000000e3, 0x000000dd, 0x000000e2, 0x00000002, 0x00000050, 0x0008004f, 0x00000007, 0x000000e4, - 0x000000e3, 0x000000e3, 0x00000000, 0x00000001, 0x00000002, 0x0004003d, 0x00000043, 0x000000e6, - 0x0000007b, 0x00050081, 0x00000014, 0x000000ed, 0x00000098, 0x000000d2, 0x00070058, 0x00000013, - 0x000000ee, 0x000000e6, 0x000000ed, 0x00000002, 0x00000050, 0x0008004f, 0x00000007, 0x000000ef, - 0x000000ee, 0x000000ee, 0x00000000, 0x00000001, 0x00000002, 0x000300f7, 0x000000f4, 0x00000000, - 0x000400fa, 0x000000a0, 0x000000f3, 0x000000f4, 0x000200f8, 0x000000f3, 0x00050080, 0x0000000a, - 0x000000f7, 0x00000065, 0x000000f6, 0x00050041, 0x00000019, 0x0000017e, 0x00000017, 0x00000018, - 0x0004003d, 0x0000000a, 0x0000017f, 0x0000017e, 0x00050082, 0x0000000a, 0x00000180, 0x000000f7, - 0x0000017f, 0x00050051, 0x00000009, 0x00000182, 0x00000180, 0x00000000, 0x000500af, 0x0000001d, - 0x00000183, 0x00000182, 0x00000023, 0x000300f7, 0x00000188, 0x00000000, 0x000400fa, 0x00000183, - 0x00000184, 0x00000188, 0x000200f8, 0x00000184, 0x00050051, 0x00000009, 0x00000186, 0x00000180, - 0x00000001, 0x000500af, 0x0000001d, 0x00000187, 0x00000186, 0x00000023, 0x000200f9, 0x00000188, - 0x000200f8, 0x00000188, 0x000700f5, 0x0000001d, 0x00000189, 0x00000183, 0x000000f3, 0x00000187, - 0x00000184, 0x000300f7, 0x00000190, 0x00000000, 0x000400fa, 0x00000189, 0x0000018a, 0x00000190, - 0x000200f8, 0x0000018a, 0x000500b1, 0x0000001d, 0x0000018f, 0x00000182, 0x0000009f, 0x000200f9, - 0x00000190, 0x000200f8, 0x00000190, 0x000700f5, 0x0000001d, 0x00000191, 0x00000189, 0x00000188, - 0x0000018f, 0x0000018a, 0x000300f7, 0x00000198, 0x00000000, 0x000400fa, 0x00000191, 0x00000192, - 0x00000198, 0x000200f8, 0x00000192, 0x00050051, 0x00000009, 0x00000194, 0x00000180, 0x00000001, - 0x00060041, 0x00000031, 0x00000195, 0x00000017, 0x00000030, 0x00000027, 0x0004003d, 0x00000009, - 0x00000196, 0x00000195, 0x000500b1, 0x0000001d, 0x00000197, 0x00000194, 0x00000196, 0x000200f9, - 0x00000198, 0x000200f8, 0x00000198, 0x000700f5, 0x0000001d, 0x00000199, 0x00000191, 0x00000190, - 0x00000197, 0x00000192, 0x000300f7, 0x000001ac, 0x00000000, 0x000400fa, 0x00000199, 0x0000019a, - 0x000001ac, 0x000200f8, 0x0000019a, 0x0004003d, 0x00000043, 0x0000019b, 0x00000045, 0x0004006f, - 0x00000014, 0x0000019d, 0x00000180, 0x00050081, 0x00000014, 0x0000019f, 0x0000019d, 0x0000026f, - 0x00050041, 0x00000019, 0x000001a0, 0x00000017, 0x00000030, 0x0004003d, 0x0000000a, 0x000001a1, - 0x000001a0, 0x0004006f, 0x00000014, 0x000001a2, 0x000001a1, 0x00050088, 0x00000014, 0x000001a3, - 0x0000019f, 0x000001a2, 0x00070058, 0x00000013, 0x000001a4, 0x0000019b, 0x000001a3, 0x00000002, - 0x00000050, 0x0008004f, 0x00000007, 0x000001a7, 0x000001a4, 0x000001a4, 0x00000002, 0x00000001, - 0x00000000, 0x00050051, 0x00000006, 0x000001a9, 0x000001a4, 0x00000003, 0x00060050, 0x00000007, - 0x000001aa, 0x000001a9, 0x000001a9, 0x000001a9, 0x0008000c, 0x00000007, 0x000001ab, 0x00000001, - 0x0000002e, 0x000000db, 0x000001a7, 0x000001aa, 0x000200f9, 0x000001ac, 0x000200f8, 0x000001ac, - 0x000700f5, 0x00000007, 0x0000023c, 0x000000db, 0x00000198, 0x000001ab, 0x0000019a, 0x00050080, - 0x0000000a, 0x000000fe, 0x00000065, 0x000000fd, 0x00050082, 0x0000000a, 0x000001b5, 0x000000fe, - 0x0000017f, 0x00050051, 0x00000009, 0x000001b7, 0x000001b5, 0x00000000, 0x000500af, 0x0000001d, - 0x000001b8, 0x000001b7, 0x00000023, 0x000300f7, 0x000001bd, 0x00000000, 0x000400fa, 0x000001b8, - 0x000001b9, 0x000001bd, 0x000200f8, 0x000001b9, 0x00050051, 0x00000009, 0x000001bb, 0x000001b5, - 0x00000001, 0x000500af, 0x0000001d, 0x000001bc, 0x000001bb, 0x00000023, 0x000200f9, 0x000001bd, - 0x000200f8, 0x000001bd, 0x000700f5, 0x0000001d, 0x000001be, 0x000001b8, 0x000001ac, 0x000001bc, - 0x000001b9, 0x000300f7, 0x000001c5, 0x00000000, 0x000400fa, 0x000001be, 0x000001bf, 0x000001c5, - 0x000200f8, 0x000001bf, 0x000500b1, 0x0000001d, 0x000001c4, 0x000001b7, 0x0000009f, 0x000200f9, - 0x000001c5, 0x000200f8, 0x000001c5, 0x000700f5, 0x0000001d, 0x000001c6, 0x000001be, 0x000001bd, - 0x000001c4, 0x000001bf, 0x000300f7, 0x000001cd, 0x00000000, 0x000400fa, 0x000001c6, 0x000001c7, - 0x000001cd, 0x000200f8, 0x000001c7, 0x00050051, 0x00000009, 0x000001c9, 0x000001b5, 0x00000001, - 0x00060041, 0x00000031, 0x000001ca, 0x00000017, 0x00000030, 0x00000027, 0x0004003d, 0x00000009, - 0x000001cb, 0x000001ca, 0x000500b1, 0x0000001d, 0x000001cc, 0x000001c9, 0x000001cb, 0x000200f9, - 0x000001cd, 0x000200f8, 0x000001cd, 0x000700f5, 0x0000001d, 0x000001ce, 0x000001c6, 0x000001c5, - 0x000001cc, 0x000001c7, 0x000300f7, 0x000001e1, 0x00000000, 0x000400fa, 0x000001ce, 0x000001cf, - 0x000001e1, 0x000200f8, 0x000001cf, 0x0004003d, 0x00000043, 0x000001d0, 0x00000045, 0x0004006f, - 0x00000014, 0x000001d2, 0x000001b5, 0x00050081, 0x00000014, 0x000001d4, 0x000001d2, 0x0000026f, - 0x00050041, 0x00000019, 0x000001d5, 0x00000017, 0x00000030, 0x0004003d, 0x0000000a, 0x000001d6, - 0x000001d5, 0x0004006f, 0x00000014, 0x000001d7, 0x000001d6, 0x00050088, 0x00000014, 0x000001d8, - 0x000001d4, 0x000001d7, 0x00070058, 0x00000013, 0x000001d9, 0x000001d0, 0x000001d8, 0x00000002, - 0x00000050, 0x0008004f, 0x00000007, 0x000001dc, 0x000001d9, 0x000001d9, 0x00000002, 0x00000001, - 0x00000000, 0x00050051, 0x00000006, 0x000001de, 0x000001d9, 0x00000003, 0x00060050, 0x00000007, - 0x000001df, 0x000001de, 0x000001de, 0x000001de, 0x0008000c, 0x00000007, 0x000001e0, 0x00000001, - 0x0000002e, 0x000000e4, 0x000001dc, 0x000001df, 0x000200f9, 0x000001e1, 0x000200f8, 0x000001e1, - 0x000700f5, 0x00000007, 0x00000244, 0x000000e4, 0x000001cd, 0x000001e0, 0x000001cf, 0x00050080, - 0x0000000a, 0x00000105, 0x00000065, 0x00000104, 0x00050082, 0x0000000a, 0x000001ea, 0x00000105, - 0x0000017f, 0x00050051, 0x00000009, 0x000001ec, 0x000001ea, 0x00000000, 0x000500af, 0x0000001d, - 0x000001ed, 0x000001ec, 0x00000023, 0x000300f7, 0x000001f2, 0x00000000, 0x000400fa, 0x000001ed, - 0x000001ee, 0x000001f2, 0x000200f8, 0x000001ee, 0x00050051, 0x00000009, 0x000001f0, 0x000001ea, - 0x00000001, 0x000500af, 0x0000001d, 0x000001f1, 0x000001f0, 0x00000023, 0x000200f9, 0x000001f2, - 0x000200f8, 0x000001f2, 0x000700f5, 0x0000001d, 0x000001f3, 0x000001ed, 0x000001e1, 0x000001f1, - 0x000001ee, 0x000300f7, 0x000001fa, 0x00000000, 0x000400fa, 0x000001f3, 0x000001f4, 0x000001fa, - 0x000200f8, 0x000001f4, 0x000500b1, 0x0000001d, 0x000001f9, 0x000001ec, 0x0000009f, 0x000200f9, - 0x000001fa, 0x000200f8, 0x000001fa, 0x000700f5, 0x0000001d, 0x000001fb, 0x000001f3, 0x000001f2, - 0x000001f9, 0x000001f4, 0x000300f7, 0x00000202, 0x00000000, 0x000400fa, 0x000001fb, 0x000001fc, - 0x00000202, 0x000200f8, 0x000001fc, 0x00050051, 0x00000009, 0x000001fe, 0x000001ea, 0x00000001, - 0x00060041, 0x00000031, 0x000001ff, 0x00000017, 0x00000030, 0x00000027, 0x0004003d, 0x00000009, - 0x00000200, 0x000001ff, 0x000500b1, 0x0000001d, 0x00000201, 0x000001fe, 0x00000200, 0x000200f9, - 0x00000202, 0x000200f8, 0x00000202, 0x000700f5, 0x0000001d, 0x00000203, 0x000001fb, 0x000001fa, - 0x00000201, 0x000001fc, 0x000300f7, 0x00000216, 0x00000000, 0x000400fa, 0x00000203, 0x00000204, - 0x00000216, 0x000200f8, 0x00000204, 0x0004003d, 0x00000043, 0x00000205, 0x00000045, 0x0004006f, - 0x00000014, 0x00000207, 0x000001ea, 0x00050081, 0x00000014, 0x00000209, 0x00000207, 0x0000026f, - 0x00050041, 0x00000019, 0x0000020a, 0x00000017, 0x00000030, 0x0004003d, 0x0000000a, 0x0000020b, - 0x0000020a, 0x0004006f, 0x00000014, 0x0000020c, 0x0000020b, 0x00050088, 0x00000014, 0x0000020d, - 0x00000209, 0x0000020c, 0x00070058, 0x00000013, 0x0000020e, 0x00000205, 0x0000020d, 0x00000002, - 0x00000050, 0x0008004f, 0x00000007, 0x00000211, 0x0000020e, 0x0000020e, 0x00000002, 0x00000001, - 0x00000000, 0x00050051, 0x00000006, 0x00000213, 0x0000020e, 0x00000003, 0x00060050, 0x00000007, - 0x00000214, 0x00000213, 0x00000213, 0x00000213, 0x0008000c, 0x00000007, 0x00000215, 0x00000001, - 0x0000002e, 0x000000ef, 0x00000211, 0x00000214, 0x000200f9, 0x00000216, 0x000200f8, 0x00000216, - 0x000700f5, 0x00000007, 0x00000250, 0x000000ef, 0x00000202, 0x00000215, 0x00000204, 0x000200f9, - 0x000000f4, 0x000200f8, 0x000000f4, 0x000700f5, 0x00000007, 0x0000026d, 0x000000ef, 0x000000cd, - 0x00000250, 0x00000216, 0x000700f5, 0x00000007, 0x00000268, 0x000000e4, 0x000000cd, 0x00000244, - 0x00000216, 0x000700f5, 0x00000007, 0x0000025f, 0x000000db, 0x000000cd, 0x0000023c, 0x00000216, - 0x00050081, 0x00000007, 0x0000010d, 0x00000238, 0x0000025f, 0x00050081, 0x00000007, 0x0000010f, - 0x0000010d, 0x00000268, 0x00050081, 0x00000007, 0x00000111, 0x0000010f, 0x0000026d, 0x0005008e, - 0x00000007, 0x00000113, 0x00000111, 0x00000112, 0x00050041, 0x000000a9, 0x00000115, 0x00000017, - 0x000000c3, 0x0004003d, 0x00000013, 0x00000116, 0x00000115, 0x0008004f, 0x00000007, 0x00000117, - 0x00000116, 0x00000116, 0x00000000, 0x00000001, 0x00000002, 0x00050094, 0x00000006, 0x00000119, - 0x00000117, 0x00000113, 0x00060041, 0x000000af, 0x0000011a, 0x00000017, 0x000000c3, 0x00000055, - 0x0004003d, 0x00000006, 0x0000011b, 0x0000011a, 0x00050081, 0x00000006, 0x0000011c, 0x00000119, - 0x0000011b, 0x00050041, 0x000000a9, 0x0000011f, 0x00000017, 0x0000011e, 0x0004003d, 0x00000013, - 0x00000120, 0x0000011f, 0x0008004f, 0x00000007, 0x00000121, 0x00000120, 0x00000120, 0x00000000, - 0x00000001, 0x00000002, 0x00050094, 0x00000006, 0x00000123, 0x00000121, 0x00000113, 0x00060041, - 0x000000af, 0x00000124, 0x00000017, 0x0000011e, 0x00000055, 0x0004003d, 0x00000006, 0x00000125, - 0x00000124, 0x00050081, 0x00000006, 0x00000126, 0x00000123, 0x00000125, 0x0004003d, 0x000000b3, - 0x00000128, 0x00000127, 0x000500c3, 0x0000000a, 0x0000012b, 0x00000065, 0x00000104, 0x00060041, - 0x000000af, 0x0000012e, 0x00000017, 0x0000012d, 0x0000001f, 0x0004003d, 0x00000006, 0x0000012f, - 0x0000012e, 0x00050085, 0x00000006, 0x00000130, 0x0000011c, 0x0000012f, 0x00060041, 0x000000af, - 0x00000131, 0x00000017, 0x0000012d, 0x00000027, 0x0004003d, 0x00000006, 0x00000132, 0x00000131, - 0x00050081, 0x00000006, 0x00000133, 0x00000130, 0x00000132, 0x00050085, 0x00000006, 0x00000137, - 0x00000126, 0x0000012f, 0x00050081, 0x00000006, 0x0000013a, 0x00000137, 0x00000132, 0x00070050, - 0x00000013, 0x0000013b, 0x00000133, 0x0000013a, 0x00000050, 0x00000050, 0x00040063, 0x00000128, - 0x0000012b, 0x0000013b, 0x000200f9, 0x000000ce, 0x000200f8, 0x000000ce, 0x000200f9, 0x0000013e, - 0x000200f8, 0x0000013e, 0x000100fd, 0x00010038, + 0x00050048, 0x00000015, 0x00000009, 0x00000023, 0x00000060, 0x00050048, 0x00000015, 0x0000000a, + 0x00000023, 0x00000068, 0x00040047, 0x00000045, 0x00000021, 0x00000003, 0x00040047, 0x00000045, + 0x00000022, 0x00000000, 0x00040047, 0x00000061, 0x0000000b, 0x0000001c, 0x00040047, 0x0000007b, + 0x00000021, 0x00000000, 0x00040047, 0x0000007b, 0x00000022, 0x00000000, 0x00030047, 0x000000bf, + 0x00000019, 0x00040047, 0x000000bf, 0x00000021, 0x00000001, 0x00040047, 0x000000bf, 0x00000022, + 0x00000000, 0x00030047, 0x0000013a, 0x00000019, 0x00040047, 0x0000013a, 0x00000021, 0x00000002, + 0x00040047, 0x0000013a, 0x00000022, 0x00000000, 0x00040047, 0x00000150, 0x0000000b, 0x00000019, + 0x00020013, 0x00000002, 0x00030021, 0x00000003, 0x00000002, 0x00030016, 0x00000006, 0x00000020, + 0x00040017, 0x00000007, 0x00000006, 0x00000003, 0x00040015, 0x00000009, 0x00000020, 0x00000001, + 0x00040017, 0x0000000a, 0x00000009, 0x00000002, 0x00040017, 0x00000013, 0x00000006, 0x00000004, + 0x00040017, 0x00000014, 0x00000006, 0x00000002, 0x000d001e, 0x00000015, 0x00000013, 0x00000013, + 0x00000013, 0x00000014, 0x00000014, 0x0000000a, 0x0000000a, 0x0000000a, 0x0000000a, 0x0000000a, + 0x00000009, 0x00040020, 0x00000016, 0x00000009, 0x00000015, 0x0004003b, 0x00000016, 0x00000017, + 0x00000009, 0x0004002b, 0x00000009, 0x00000018, 0x00000008, 0x00040020, 0x00000019, 0x00000009, + 0x0000000a, 0x00020014, 0x0000001d, 0x00040015, 0x0000001e, 0x00000020, 0x00000000, 0x0004002b, + 0x0000001e, 0x0000001f, 0x00000000, 0x0004002b, 0x00000009, 0x00000023, 0x00000000, 0x0004002b, + 0x0000001e, 0x00000027, 0x00000001, 0x0004002b, 0x00000009, 0x00000030, 0x00000009, 0x00040020, + 0x00000031, 0x00000009, 0x00000009, 0x00090019, 0x00000042, 0x00000006, 0x00000001, 0x00000000, + 0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x0003001b, 0x00000043, 0x00000042, 0x00040020, + 0x00000044, 0x00000000, 0x00000043, 0x0004003b, 0x00000044, 0x00000045, 0x00000000, 0x0004002b, + 0x00000006, 0x00000049, 0x3f000000, 0x0004002b, 0x00000006, 0x00000050, 0x00000000, 0x0004002b, + 0x0000001e, 0x00000055, 0x00000003, 0x00040017, 0x0000005f, 0x0000001e, 0x00000003, 0x00040020, + 0x00000060, 0x00000001, 0x0000005f, 0x0004003b, 0x00000060, 0x00000061, 0x00000001, 0x00040017, + 0x00000062, 0x0000001e, 0x00000002, 0x0004002b, 0x00000009, 0x00000068, 0x00000007, 0x0004002b, + 0x00000006, 0x0000007a, 0x3f800000, 0x0004003b, 0x00000044, 0x0000007b, 0x00000000, 0x0004002b, + 0x00000009, 0x00000083, 0x00000006, 0x0004002b, 0x00000009, 0x0000008c, 0x00000005, 0x0004002b, + 0x00000009, 0x00000099, 0x0000000a, 0x00040020, 0x000000b3, 0x00000009, 0x00000013, 0x00040020, + 0x000000b9, 0x00000009, 0x00000006, 0x00090019, 0x000000bd, 0x00000006, 0x00000001, 0x00000000, + 0x00000000, 0x00000000, 0x00000002, 0x00000000, 0x00040020, 0x000000be, 0x00000000, 0x000000bd, + 0x0004003b, 0x000000be, 0x000000bf, 0x00000000, 0x0004002b, 0x00000009, 0x000000c3, 0x00000003, + 0x0004002b, 0x00000009, 0x000000cd, 0x00000001, 0x0005002c, 0x0000000a, 0x00000109, 0x000000cd, + 0x00000023, 0x0005002c, 0x0000000a, 0x00000110, 0x00000023, 0x000000cd, 0x0005002c, 0x0000000a, + 0x00000117, 0x000000cd, 0x000000cd, 0x0004002b, 0x00000006, 0x00000125, 0x3e800000, 0x0004002b, + 0x00000009, 0x00000131, 0x00000002, 0x0004003b, 0x000000be, 0x0000013a, 0x00000000, 0x0004002b, + 0x00000009, 0x00000140, 0x00000004, 0x0004002b, 0x0000001e, 0x0000014f, 0x00000010, 0x0006002c, + 0x0000005f, 0x00000150, 0x0000014f, 0x0000014f, 0x00000027, 0x0005002c, 0x00000014, 0x00000291, + 0x0000007a, 0x0000007a, 0x0005002c, 0x00000014, 0x00000292, 0x00000049, 0x00000049, 0x00050036, + 0x00000002, 0x00000004, 0x00000000, 0x00000003, 0x000200f8, 0x00000005, 0x000300f7, 0x00000151, + 0x00000000, 0x000300fb, 0x0000001f, 0x00000152, 0x000200f8, 0x00000152, 0x0004003d, 0x0000005f, + 0x00000063, 0x00000061, 0x0007004f, 0x00000062, 0x00000064, 0x00000063, 0x00000063, 0x00000000, + 0x00000001, 0x0004007c, 0x0000000a, 0x00000065, 0x00000064, 0x00050051, 0x00000009, 0x00000067, + 0x00000065, 0x00000000, 0x00060041, 0x00000031, 0x00000069, 0x00000017, 0x00000068, 0x0000001f, + 0x0004003d, 0x00000009, 0x0000006a, 0x00000069, 0x000500af, 0x0000001d, 0x0000006b, 0x00000067, + 0x0000006a, 0x000400a8, 0x0000001d, 0x0000006c, 0x0000006b, 0x000300f7, 0x0000006e, 0x00000000, + 0x000400fa, 0x0000006c, 0x0000006d, 0x0000006e, 0x000200f8, 0x0000006d, 0x00050051, 0x00000009, + 0x00000070, 0x00000065, 0x00000001, 0x00060041, 0x00000031, 0x00000071, 0x00000017, 0x00000068, + 0x00000027, 0x0004003d, 0x00000009, 0x00000072, 0x00000071, 0x000500af, 0x0000001d, 0x00000073, + 0x00000070, 0x00000072, 0x000200f9, 0x0000006e, 0x000200f8, 0x0000006e, 0x000700f5, 0x0000001d, + 0x00000074, 0x0000006b, 0x00000152, 0x00000073, 0x0000006d, 0x000300f7, 0x00000076, 0x00000000, + 0x000400fa, 0x00000074, 0x00000075, 0x00000076, 0x000200f8, 0x00000075, 0x000200f9, 0x00000151, + 0x000200f8, 0x00000076, 0x0004003d, 0x00000043, 0x0000007c, 0x0000007b, 0x00040064, 0x00000042, + 0x0000007d, 0x0000007c, 0x00050067, 0x0000000a, 0x0000007e, 0x0000007d, 0x00000023, 0x0004006f, + 0x00000014, 0x0000007f, 0x0000007e, 0x00050088, 0x00000014, 0x00000081, 0x00000291, 0x0000007f, + 0x00050041, 0x00000019, 0x00000084, 0x00000017, 0x00000083, 0x0004003d, 0x0000000a, 0x00000085, + 0x00000084, 0x0004006f, 0x00000014, 0x00000086, 0x00000085, 0x00050041, 0x00000019, 0x00000087, + 0x00000017, 0x00000068, 0x0004003d, 0x0000000a, 0x00000088, 0x00000087, 0x0004006f, 0x00000014, + 0x00000089, 0x00000088, 0x00050088, 0x00000014, 0x0000008a, 0x00000086, 0x00000089, 0x00050041, + 0x00000019, 0x0000008d, 0x00000017, 0x0000008c, 0x0004003d, 0x0000000a, 0x0000008e, 0x0000008d, + 0x0004006f, 0x00000014, 0x0000008f, 0x0000008e, 0x0004006f, 0x00000014, 0x00000091, 0x00000065, + 0x00050081, 0x00000014, 0x00000093, 0x00000091, 0x00000292, 0x00050085, 0x00000014, 0x00000095, + 0x00000093, 0x0000008a, 0x00050081, 0x00000014, 0x00000096, 0x0000008f, 0x00000095, 0x00050085, + 0x00000014, 0x00000098, 0x00000096, 0x00000081, 0x00050041, 0x00000031, 0x0000009a, 0x00000017, + 0x00000099, 0x0004003d, 0x00000009, 0x0000009b, 0x0000009a, 0x000500ab, 0x0000001d, 0x0000009c, + 0x0000009b, 0x00000023, 0x000300f7, 0x0000009e, 0x00000000, 0x000400fa, 0x0000009c, 0x0000009d, + 0x0000009e, 0x000200f8, 0x0000009d, 0x00050051, 0x00000006, 0x000000a0, 0x00000098, 0x00000001, + 0x00050083, 0x00000006, 0x000000a1, 0x0000007a, 0x000000a0, 0x00060052, 0x00000014, 0x0000022f, + 0x000000a1, 0x00000098, 0x00000001, 0x000200f9, 0x0000009e, 0x000200f8, 0x0000009e, 0x000700f5, + 0x00000014, 0x0000024d, 0x00000098, 0x00000076, 0x0000022f, 0x0000009d, 0x0004003d, 0x00000043, + 0x000000a4, 0x0000007b, 0x00070058, 0x00000013, 0x000000a6, 0x000000a4, 0x0000024d, 0x00000002, + 0x00000050, 0x0008004f, 0x00000007, 0x000000a7, 0x000000a6, 0x000000a6, 0x00000000, 0x00000001, + 0x00000002, 0x00060041, 0x00000031, 0x000000a8, 0x00000017, 0x00000030, 0x0000001f, 0x0004003d, + 0x00000009, 0x000000a9, 0x000000a8, 0x000500ad, 0x0000001d, 0x000000aa, 0x000000a9, 0x00000023, + 0x000300f7, 0x000000ac, 0x00000000, 0x000400fa, 0x000000aa, 0x000000ab, 0x000000ac, 0x000200f8, + 0x000000ab, 0x00050041, 0x00000019, 0x0000015c, 0x00000017, 0x00000018, 0x0004003d, 0x0000000a, + 0x0000015d, 0x0000015c, 0x00050082, 0x0000000a, 0x0000015e, 0x00000065, 0x0000015d, 0x00050051, + 0x00000009, 0x00000160, 0x0000015e, 0x00000000, 0x000500af, 0x0000001d, 0x00000161, 0x00000160, + 0x00000023, 0x000300f7, 0x00000166, 0x00000000, 0x000400fa, 0x00000161, 0x00000162, 0x00000166, + 0x000200f8, 0x00000162, 0x00050051, 0x00000009, 0x00000164, 0x0000015e, 0x00000001, 0x000500af, + 0x0000001d, 0x00000165, 0x00000164, 0x00000023, 0x000200f9, 0x00000166, 0x000200f8, 0x00000166, + 0x000700f5, 0x0000001d, 0x00000167, 0x00000161, 0x000000ab, 0x00000165, 0x00000162, 0x000300f7, + 0x0000016e, 0x00000000, 0x000400fa, 0x00000167, 0x00000168, 0x0000016e, 0x000200f8, 0x00000168, + 0x000500b1, 0x0000001d, 0x0000016d, 0x00000160, 0x000000a9, 0x000200f9, 0x0000016e, 0x000200f8, + 0x0000016e, 0x000700f5, 0x0000001d, 0x0000016f, 0x00000167, 0x00000166, 0x0000016d, 0x00000168, + 0x000300f7, 0x00000176, 0x00000000, 0x000400fa, 0x0000016f, 0x00000170, 0x00000176, 0x000200f8, + 0x00000170, 0x00050051, 0x00000009, 0x00000172, 0x0000015e, 0x00000001, 0x00060041, 0x00000031, + 0x00000173, 0x00000017, 0x00000030, 0x00000027, 0x0004003d, 0x00000009, 0x00000174, 0x00000173, + 0x000500b1, 0x0000001d, 0x00000175, 0x00000172, 0x00000174, 0x000200f9, 0x00000176, 0x000200f8, + 0x00000176, 0x000700f5, 0x0000001d, 0x00000177, 0x0000016f, 0x0000016e, 0x00000175, 0x00000170, + 0x000300f7, 0x0000018a, 0x00000000, 0x000400fa, 0x00000177, 0x00000178, 0x0000018a, 0x000200f8, + 0x00000178, 0x0004003d, 0x00000043, 0x00000179, 0x00000045, 0x0004006f, 0x00000014, 0x0000017b, + 0x0000015e, 0x00050081, 0x00000014, 0x0000017d, 0x0000017b, 0x00000292, 0x00050041, 0x00000019, + 0x0000017e, 0x00000017, 0x00000030, 0x0004003d, 0x0000000a, 0x0000017f, 0x0000017e, 0x0004006f, + 0x00000014, 0x00000180, 0x0000017f, 0x00050088, 0x00000014, 0x00000181, 0x0000017d, 0x00000180, + 0x00070058, 0x00000013, 0x00000182, 0x00000179, 0x00000181, 0x00000002, 0x00000050, 0x0008004f, + 0x00000007, 0x00000185, 0x00000182, 0x00000182, 0x00000002, 0x00000001, 0x00000000, 0x00050051, + 0x00000006, 0x00000187, 0x00000182, 0x00000003, 0x00060050, 0x00000007, 0x00000188, 0x00000187, + 0x00000187, 0x00000187, 0x0008000c, 0x00000007, 0x00000189, 0x00000001, 0x0000002e, 0x000000a7, + 0x00000185, 0x00000188, 0x000200f9, 0x0000018a, 0x000200f8, 0x0000018a, 0x000700f5, 0x00000007, + 0x00000251, 0x000000a7, 0x00000176, 0x00000189, 0x00000178, 0x000200f9, 0x000000ac, 0x000200f8, + 0x000000ac, 0x000700f5, 0x00000007, 0x00000252, 0x000000a7, 0x0000009e, 0x00000251, 0x0000018a, + 0x00050041, 0x000000b3, 0x000000b4, 0x00000017, 0x00000023, 0x0004003d, 0x00000013, 0x000000b5, + 0x000000b4, 0x0008004f, 0x00000007, 0x000000b6, 0x000000b5, 0x000000b5, 0x00000000, 0x00000001, + 0x00000002, 0x00050094, 0x00000006, 0x000000b8, 0x000000b6, 0x00000252, 0x00060041, 0x000000b9, + 0x000000ba, 0x00000017, 0x00000023, 0x00000055, 0x0004003d, 0x00000006, 0x000000bb, 0x000000ba, + 0x00050081, 0x00000006, 0x000000bc, 0x000000b8, 0x000000bb, 0x0004003d, 0x000000bd, 0x000000c0, + 0x000000bf, 0x00060041, 0x000000b9, 0x000000c4, 0x00000017, 0x000000c3, 0x0000001f, 0x0004003d, + 0x00000006, 0x000000c5, 0x000000c4, 0x00050085, 0x00000006, 0x000000c6, 0x000000bc, 0x000000c5, + 0x00060041, 0x000000b9, 0x000000c7, 0x00000017, 0x000000c3, 0x00000027, 0x0004003d, 0x00000006, + 0x000000c8, 0x000000c7, 0x00050081, 0x00000006, 0x000000c9, 0x000000c6, 0x000000c8, 0x00070050, + 0x00000013, 0x000000ca, 0x000000c9, 0x00000050, 0x00000050, 0x00000050, 0x00040063, 0x000000c0, + 0x00000065, 0x000000ca, 0x000500c7, 0x00000009, 0x000000ce, 0x00000067, 0x000000cd, 0x000500aa, + 0x0000001d, 0x000000cf, 0x000000ce, 0x00000023, 0x000300f7, 0x000000d1, 0x00000000, 0x000400fa, + 0x000000cf, 0x000000d0, 0x000000d1, 0x000200f8, 0x000000d0, 0x00050051, 0x00000009, 0x000000d3, + 0x00000065, 0x00000001, 0x000500c7, 0x00000009, 0x000000d4, 0x000000d3, 0x000000cd, 0x000500aa, + 0x0000001d, 0x000000d5, 0x000000d4, 0x00000023, 0x000200f9, 0x000000d1, 0x000200f8, 0x000000d1, + 0x000700f5, 0x0000001d, 0x000000d6, 0x000000cf, 0x000000ac, 0x000000d5, 0x000000d0, 0x000300f7, + 0x000000d8, 0x00000000, 0x000400fa, 0x000000d6, 0x000000d7, 0x000000d8, 0x000200f8, 0x000000d7, + 0x00050085, 0x00000014, 0x000000dc, 0x0000008a, 0x00000081, 0x000300f7, 0x000000e1, 0x00000000, + 0x000400fa, 0x0000009c, 0x000000e0, 0x000000e1, 0x000200f8, 0x000000e0, 0x00050051, 0x00000006, + 0x000000e3, 0x000000dc, 0x00000001, 0x0004007f, 0x00000006, 0x000000e4, 0x000000e3, 0x00060052, + 0x00000014, 0x00000239, 0x000000e4, 0x000000dc, 0x00000001, 0x000200f9, 0x000000e1, 0x000200f8, + 0x000000e1, 0x000700f5, 0x00000014, 0x0000025a, 0x000000dc, 0x000000d7, 0x00000239, 0x000000e0, + 0x0004003d, 0x00000043, 0x000000e7, 0x0000007b, 0x00050051, 0x00000006, 0x000000ea, 0x0000025a, + 0x00000000, 0x00050050, 0x00000014, 0x000000eb, 0x000000ea, 0x00000050, 0x00050081, 0x00000014, + 0x000000ec, 0x0000024d, 0x000000eb, 0x00070058, 0x00000013, 0x000000ed, 0x000000e7, 0x000000ec, + 0x00000002, 0x00000050, 0x0008004f, 0x00000007, 0x000000ee, 0x000000ed, 0x000000ed, 0x00000000, + 0x00000001, 0x00000002, 0x0004003d, 0x00000043, 0x000000f0, 0x0000007b, 0x00050051, 0x00000006, + 0x000000f3, 0x0000025a, 0x00000001, 0x00050050, 0x00000014, 0x000000f4, 0x00000050, 0x000000f3, + 0x00050081, 0x00000014, 0x000000f5, 0x0000024d, 0x000000f4, 0x00070058, 0x00000013, 0x000000f6, + 0x000000f0, 0x000000f5, 0x00000002, 0x00000050, 0x0008004f, 0x00000007, 0x000000f7, 0x000000f6, + 0x000000f6, 0x00000000, 0x00000001, 0x00000002, 0x0004003d, 0x00000043, 0x000000f9, 0x0000007b, + 0x00050081, 0x00000014, 0x00000100, 0x0000024d, 0x0000025a, 0x00070058, 0x00000013, 0x00000101, + 0x000000f9, 0x00000100, 0x00000002, 0x00000050, 0x0008004f, 0x00000007, 0x00000102, 0x00000101, + 0x00000101, 0x00000000, 0x00000001, 0x00000002, 0x000300f7, 0x00000107, 0x00000000, 0x000400fa, + 0x000000aa, 0x00000106, 0x00000107, 0x000200f8, 0x00000106, 0x00050080, 0x0000000a, 0x0000010a, + 0x00000065, 0x00000109, 0x00050041, 0x00000019, 0x00000191, 0x00000017, 0x00000018, 0x0004003d, + 0x0000000a, 0x00000192, 0x00000191, 0x00050082, 0x0000000a, 0x00000193, 0x0000010a, 0x00000192, + 0x00050051, 0x00000009, 0x00000195, 0x00000193, 0x00000000, 0x000500af, 0x0000001d, 0x00000196, + 0x00000195, 0x00000023, 0x000300f7, 0x0000019b, 0x00000000, 0x000400fa, 0x00000196, 0x00000197, + 0x0000019b, 0x000200f8, 0x00000197, 0x00050051, 0x00000009, 0x00000199, 0x00000193, 0x00000001, + 0x000500af, 0x0000001d, 0x0000019a, 0x00000199, 0x00000023, 0x000200f9, 0x0000019b, 0x000200f8, + 0x0000019b, 0x000700f5, 0x0000001d, 0x0000019c, 0x00000196, 0x00000106, 0x0000019a, 0x00000197, + 0x000300f7, 0x000001a3, 0x00000000, 0x000400fa, 0x0000019c, 0x0000019d, 0x000001a3, 0x000200f8, + 0x0000019d, 0x000500b1, 0x0000001d, 0x000001a2, 0x00000195, 0x000000a9, 0x000200f9, 0x000001a3, + 0x000200f8, 0x000001a3, 0x000700f5, 0x0000001d, 0x000001a4, 0x0000019c, 0x0000019b, 0x000001a2, + 0x0000019d, 0x000300f7, 0x000001ab, 0x00000000, 0x000400fa, 0x000001a4, 0x000001a5, 0x000001ab, + 0x000200f8, 0x000001a5, 0x00050051, 0x00000009, 0x000001a7, 0x00000193, 0x00000001, 0x00060041, + 0x00000031, 0x000001a8, 0x00000017, 0x00000030, 0x00000027, 0x0004003d, 0x00000009, 0x000001a9, + 0x000001a8, 0x000500b1, 0x0000001d, 0x000001aa, 0x000001a7, 0x000001a9, 0x000200f9, 0x000001ab, + 0x000200f8, 0x000001ab, 0x000700f5, 0x0000001d, 0x000001ac, 0x000001a4, 0x000001a3, 0x000001aa, + 0x000001a5, 0x000300f7, 0x000001bf, 0x00000000, 0x000400fa, 0x000001ac, 0x000001ad, 0x000001bf, + 0x000200f8, 0x000001ad, 0x0004003d, 0x00000043, 0x000001ae, 0x00000045, 0x0004006f, 0x00000014, + 0x000001b0, 0x00000193, 0x00050081, 0x00000014, 0x000001b2, 0x000001b0, 0x00000292, 0x00050041, + 0x00000019, 0x000001b3, 0x00000017, 0x00000030, 0x0004003d, 0x0000000a, 0x000001b4, 0x000001b3, + 0x0004006f, 0x00000014, 0x000001b5, 0x000001b4, 0x00050088, 0x00000014, 0x000001b6, 0x000001b2, + 0x000001b5, 0x00070058, 0x00000013, 0x000001b7, 0x000001ae, 0x000001b6, 0x00000002, 0x00000050, + 0x0008004f, 0x00000007, 0x000001ba, 0x000001b7, 0x000001b7, 0x00000002, 0x00000001, 0x00000000, + 0x00050051, 0x00000006, 0x000001bc, 0x000001b7, 0x00000003, 0x00060050, 0x00000007, 0x000001bd, + 0x000001bc, 0x000001bc, 0x000001bc, 0x0008000c, 0x00000007, 0x000001be, 0x00000001, 0x0000002e, + 0x000000ee, 0x000001ba, 0x000001bd, 0x000200f9, 0x000001bf, 0x000200f8, 0x000001bf, 0x000700f5, + 0x00000007, 0x0000025e, 0x000000ee, 0x000001ab, 0x000001be, 0x000001ad, 0x00050080, 0x0000000a, + 0x00000111, 0x00000065, 0x00000110, 0x00050082, 0x0000000a, 0x000001c8, 0x00000111, 0x00000192, + 0x00050051, 0x00000009, 0x000001ca, 0x000001c8, 0x00000000, 0x000500af, 0x0000001d, 0x000001cb, + 0x000001ca, 0x00000023, 0x000300f7, 0x000001d0, 0x00000000, 0x000400fa, 0x000001cb, 0x000001cc, + 0x000001d0, 0x000200f8, 0x000001cc, 0x00050051, 0x00000009, 0x000001ce, 0x000001c8, 0x00000001, + 0x000500af, 0x0000001d, 0x000001cf, 0x000001ce, 0x00000023, 0x000200f9, 0x000001d0, 0x000200f8, + 0x000001d0, 0x000700f5, 0x0000001d, 0x000001d1, 0x000001cb, 0x000001bf, 0x000001cf, 0x000001cc, + 0x000300f7, 0x000001d8, 0x00000000, 0x000400fa, 0x000001d1, 0x000001d2, 0x000001d8, 0x000200f8, + 0x000001d2, 0x000500b1, 0x0000001d, 0x000001d7, 0x000001ca, 0x000000a9, 0x000200f9, 0x000001d8, + 0x000200f8, 0x000001d8, 0x000700f5, 0x0000001d, 0x000001d9, 0x000001d1, 0x000001d0, 0x000001d7, + 0x000001d2, 0x000300f7, 0x000001e0, 0x00000000, 0x000400fa, 0x000001d9, 0x000001da, 0x000001e0, + 0x000200f8, 0x000001da, 0x00050051, 0x00000009, 0x000001dc, 0x000001c8, 0x00000001, 0x00060041, + 0x00000031, 0x000001dd, 0x00000017, 0x00000030, 0x00000027, 0x0004003d, 0x00000009, 0x000001de, + 0x000001dd, 0x000500b1, 0x0000001d, 0x000001df, 0x000001dc, 0x000001de, 0x000200f9, 0x000001e0, + 0x000200f8, 0x000001e0, 0x000700f5, 0x0000001d, 0x000001e1, 0x000001d9, 0x000001d8, 0x000001df, + 0x000001da, 0x000300f7, 0x000001f4, 0x00000000, 0x000400fa, 0x000001e1, 0x000001e2, 0x000001f4, + 0x000200f8, 0x000001e2, 0x0004003d, 0x00000043, 0x000001e3, 0x00000045, 0x0004006f, 0x00000014, + 0x000001e5, 0x000001c8, 0x00050081, 0x00000014, 0x000001e7, 0x000001e5, 0x00000292, 0x00050041, + 0x00000019, 0x000001e8, 0x00000017, 0x00000030, 0x0004003d, 0x0000000a, 0x000001e9, 0x000001e8, + 0x0004006f, 0x00000014, 0x000001ea, 0x000001e9, 0x00050088, 0x00000014, 0x000001eb, 0x000001e7, + 0x000001ea, 0x00070058, 0x00000013, 0x000001ec, 0x000001e3, 0x000001eb, 0x00000002, 0x00000050, + 0x0008004f, 0x00000007, 0x000001ef, 0x000001ec, 0x000001ec, 0x00000002, 0x00000001, 0x00000000, + 0x00050051, 0x00000006, 0x000001f1, 0x000001ec, 0x00000003, 0x00060050, 0x00000007, 0x000001f2, + 0x000001f1, 0x000001f1, 0x000001f1, 0x0008000c, 0x00000007, 0x000001f3, 0x00000001, 0x0000002e, + 0x000000f7, 0x000001ef, 0x000001f2, 0x000200f9, 0x000001f4, 0x000200f8, 0x000001f4, 0x000700f5, + 0x00000007, 0x00000266, 0x000000f7, 0x000001e0, 0x000001f3, 0x000001e2, 0x00050080, 0x0000000a, + 0x00000118, 0x00000065, 0x00000117, 0x00050082, 0x0000000a, 0x000001fd, 0x00000118, 0x00000192, + 0x00050051, 0x00000009, 0x000001ff, 0x000001fd, 0x00000000, 0x000500af, 0x0000001d, 0x00000200, + 0x000001ff, 0x00000023, 0x000300f7, 0x00000205, 0x00000000, 0x000400fa, 0x00000200, 0x00000201, + 0x00000205, 0x000200f8, 0x00000201, 0x00050051, 0x00000009, 0x00000203, 0x000001fd, 0x00000001, + 0x000500af, 0x0000001d, 0x00000204, 0x00000203, 0x00000023, 0x000200f9, 0x00000205, 0x000200f8, + 0x00000205, 0x000700f5, 0x0000001d, 0x00000206, 0x00000200, 0x000001f4, 0x00000204, 0x00000201, + 0x000300f7, 0x0000020d, 0x00000000, 0x000400fa, 0x00000206, 0x00000207, 0x0000020d, 0x000200f8, + 0x00000207, 0x000500b1, 0x0000001d, 0x0000020c, 0x000001ff, 0x000000a9, 0x000200f9, 0x0000020d, + 0x000200f8, 0x0000020d, 0x000700f5, 0x0000001d, 0x0000020e, 0x00000206, 0x00000205, 0x0000020c, + 0x00000207, 0x000300f7, 0x00000215, 0x00000000, 0x000400fa, 0x0000020e, 0x0000020f, 0x00000215, + 0x000200f8, 0x0000020f, 0x00050051, 0x00000009, 0x00000211, 0x000001fd, 0x00000001, 0x00060041, + 0x00000031, 0x00000212, 0x00000017, 0x00000030, 0x00000027, 0x0004003d, 0x00000009, 0x00000213, + 0x00000212, 0x000500b1, 0x0000001d, 0x00000214, 0x00000211, 0x00000213, 0x000200f9, 0x00000215, + 0x000200f8, 0x00000215, 0x000700f5, 0x0000001d, 0x00000216, 0x0000020e, 0x0000020d, 0x00000214, + 0x0000020f, 0x000300f7, 0x00000229, 0x00000000, 0x000400fa, 0x00000216, 0x00000217, 0x00000229, + 0x000200f8, 0x00000217, 0x0004003d, 0x00000043, 0x00000218, 0x00000045, 0x0004006f, 0x00000014, + 0x0000021a, 0x000001fd, 0x00050081, 0x00000014, 0x0000021c, 0x0000021a, 0x00000292, 0x00050041, + 0x00000019, 0x0000021d, 0x00000017, 0x00000030, 0x0004003d, 0x0000000a, 0x0000021e, 0x0000021d, + 0x0004006f, 0x00000014, 0x0000021f, 0x0000021e, 0x00050088, 0x00000014, 0x00000220, 0x0000021c, + 0x0000021f, 0x00070058, 0x00000013, 0x00000221, 0x00000218, 0x00000220, 0x00000002, 0x00000050, + 0x0008004f, 0x00000007, 0x00000224, 0x00000221, 0x00000221, 0x00000002, 0x00000001, 0x00000000, + 0x00050051, 0x00000006, 0x00000226, 0x00000221, 0x00000003, 0x00060050, 0x00000007, 0x00000227, + 0x00000226, 0x00000226, 0x00000226, 0x0008000c, 0x00000007, 0x00000228, 0x00000001, 0x0000002e, + 0x00000102, 0x00000224, 0x00000227, 0x000200f9, 0x00000229, 0x000200f8, 0x00000229, 0x000700f5, + 0x00000007, 0x00000272, 0x00000102, 0x00000215, 0x00000228, 0x00000217, 0x000200f9, 0x00000107, + 0x000200f8, 0x00000107, 0x000700f5, 0x00000007, 0x00000290, 0x00000102, 0x000000e1, 0x00000272, + 0x00000229, 0x000700f5, 0x00000007, 0x0000028b, 0x000000f7, 0x000000e1, 0x00000266, 0x00000229, + 0x000700f5, 0x00000007, 0x00000282, 0x000000ee, 0x000000e1, 0x0000025e, 0x00000229, 0x00050081, + 0x00000007, 0x00000120, 0x00000252, 0x00000282, 0x00050081, 0x00000007, 0x00000122, 0x00000120, + 0x0000028b, 0x00050081, 0x00000007, 0x00000124, 0x00000122, 0x00000290, 0x0005008e, 0x00000007, + 0x00000126, 0x00000124, 0x00000125, 0x00050041, 0x000000b3, 0x00000128, 0x00000017, 0x000000cd, + 0x0004003d, 0x00000013, 0x00000129, 0x00000128, 0x0008004f, 0x00000007, 0x0000012a, 0x00000129, + 0x00000129, 0x00000000, 0x00000001, 0x00000002, 0x00050094, 0x00000006, 0x0000012c, 0x0000012a, + 0x00000126, 0x00060041, 0x000000b9, 0x0000012d, 0x00000017, 0x000000cd, 0x00000055, 0x0004003d, + 0x00000006, 0x0000012e, 0x0000012d, 0x00050081, 0x00000006, 0x0000012f, 0x0000012c, 0x0000012e, + 0x00050041, 0x000000b3, 0x00000132, 0x00000017, 0x00000131, 0x0004003d, 0x00000013, 0x00000133, + 0x00000132, 0x0008004f, 0x00000007, 0x00000134, 0x00000133, 0x00000133, 0x00000000, 0x00000001, + 0x00000002, 0x00050094, 0x00000006, 0x00000136, 0x00000134, 0x00000126, 0x00060041, 0x000000b9, + 0x00000137, 0x00000017, 0x00000131, 0x00000055, 0x0004003d, 0x00000006, 0x00000138, 0x00000137, + 0x00050081, 0x00000006, 0x00000139, 0x00000136, 0x00000138, 0x0004003d, 0x000000bd, 0x0000013b, + 0x0000013a, 0x000500c3, 0x0000000a, 0x0000013e, 0x00000065, 0x00000117, 0x00060041, 0x000000b9, + 0x00000141, 0x00000017, 0x00000140, 0x0000001f, 0x0004003d, 0x00000006, 0x00000142, 0x00000141, + 0x00050085, 0x00000006, 0x00000143, 0x0000012f, 0x00000142, 0x00060041, 0x000000b9, 0x00000144, + 0x00000017, 0x00000140, 0x00000027, 0x0004003d, 0x00000006, 0x00000145, 0x00000144, 0x00050081, + 0x00000006, 0x00000146, 0x00000143, 0x00000145, 0x00050085, 0x00000006, 0x0000014a, 0x00000139, + 0x00000142, 0x00050081, 0x00000006, 0x0000014d, 0x0000014a, 0x00000145, 0x00070050, 0x00000013, + 0x0000014e, 0x00000146, 0x0000014d, 0x00000050, 0x00000050, 0x00040063, 0x0000013b, 0x0000013e, + 0x0000014e, 0x000200f9, 0x000000d8, 0x000200f8, 0x000000d8, 0x000200f9, 0x00000151, 0x000200f8, + 0x00000151, 0x000100fd, 0x00010038, }; static const size_t rgb2yuv_comp_spv_size = rgb2yuv_comp_spv.size() * sizeof(uint32_t); diff --git a/src/platform/linux/vulkan_encode.cpp b/src/platform/linux/vulkan_encode.cpp index 86983397272..bb2ec72346a 100644 --- a/src/platform/linux/vulkan_encode.cpp +++ b/src/platform/linux/vulkan_encode.cpp @@ -98,6 +98,7 @@ namespace vk { std::array dst_size; std::array cursor_pos; std::array cursor_size; + int32_t y_invert; }; // Helper to check VkResult @@ -271,6 +272,7 @@ namespace vk { push.src_size[1] = height; push.dst_size[0] = frame->width; push.dst_size[1] = frame->height; + push.y_invert = descriptor.y_invert ? 1 : 0; if (descriptor.data) { float scale_x = (float) frame->width / width; diff --git a/src/platform/linux/wayland.h b/src/platform/linux/wayland.h index 286c247bb52..d765950f887 100644 --- a/src/platform/linux/wayland.h +++ b/src/platform/linux/wayland.h @@ -69,6 +69,7 @@ namespace wl { std::array frames; frame_t *current_frame; zwlr_screencopy_frame_v1_listener listener; + bool y_invert {false}; private: bool init_gbm(); @@ -95,7 +96,6 @@ namespace wl { struct gbm_device *gbm_device {nullptr}; struct gbm_bo *current_bo {nullptr}; struct wl_buffer *current_wl_buffer {nullptr}; - bool y_invert {false}; }; class monitor_t { diff --git a/src/platform/linux/wlgrab.cpp b/src/platform/linux/wlgrab.cpp index 53823e28953..917ea8614bb 100644 --- a/src/platform/linux/wlgrab.cpp +++ b/src/platform/linux/wlgrab.cpp @@ -349,6 +349,7 @@ namespace wl { img->sd = current_frame->sd; img->frame_timestamp = current_frame->frame_timestamp; + img->y_invert = dmabuf.y_invert; // Prevent dmabuf from closing the file descriptors. std::fill_n(current_frame->sd.fds, 4, -1); From 3dcf7e26917c314fb96c70ab62b7599db1ca29a1 Mon Sep 17 00:00:00 2001 From: neatnoise Date: Wed, 18 Mar 2026 11:49:42 +0100 Subject: [PATCH 22/29] Fix corrupted image (colored boxes) in wlroots Vulkan capture Force linear GBM buffer allocation to prevent tiling/modifier mismatch when importing DMA-BUF into Vulkan. --- src/platform/linux/wayland.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/linux/wayland.cpp b/src/platform/linux/wayland.cpp index 03765629e40..6d6195ffce2 100644 --- a/src/platform/linux/wayland.cpp +++ b/src/platform/linux/wayland.cpp @@ -374,7 +374,7 @@ namespace wl { } // Create GBM buffer - current_bo = gbm_bo_create(gbm_device, dmabuf_info.width, dmabuf_info.height, dmabuf_info.format, GBM_BO_USE_RENDERING); + current_bo = gbm_bo_create(gbm_device, dmabuf_info.width, dmabuf_info.height, dmabuf_info.format, GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR); if (!current_bo) { BOOST_LOG(error) << "Failed to create GBM buffer"sv; zwlr_screencopy_frame_v1_destroy(frame); From c97a6e41d6cf7620ce93c341d89159833d0b53a8 Mon Sep 17 00:00:00 2001 From: neatnoise Date: Wed, 18 Mar 2026 16:13:07 +0100 Subject: [PATCH 23/29] Build Vulkan shaders at compile time instead of shipping pre-compiled SPIR-V - Move rgb2yuv.comp to src_assets/linux/assets/shaders/vulkan/ - Remove pre-compiled .spv and .spv.h from repo - Add CMake rules to compile .comp -> .spv -> C include at build time - Prefer glslc, fall back to glslangValidator for Ubuntu 22.04 support - Add shader compiler build dependencies for all supported distros --- .github/workflows/ci-freebsd.yml | 1 + .github/workflows/ci-linux.yml | 1 + cmake/compile_definitions/linux.cmake | 45 +++ cmake/scripts/binary_to_c.cmake | 33 +++ packaging/linux/Arch/PKGBUILD | 1 + packaging/linux/copr/Sunshine.spec | 1 + scripts/linux_build.sh | 3 + src/platform/linux/shaders/rgb2yuv.spv | Bin 7820 -> 0 bytes src/platform/linux/shaders/rgb2yuv.spv.h | 257 ------------------ src/platform/linux/vulkan_encode.cpp | 10 +- .../linux/assets/shaders/vulkan}/rgb2yuv.comp | 0 11 files changed, 93 insertions(+), 259 deletions(-) create mode 100644 cmake/scripts/binary_to_c.cmake delete mode 100644 src/platform/linux/shaders/rgb2yuv.spv delete mode 100644 src/platform/linux/shaders/rgb2yuv.spv.h rename {src/platform/linux/shaders => src_assets/linux/assets/shaders/vulkan}/rgb2yuv.comp (100%) diff --git a/.github/workflows/ci-freebsd.yml b/.github/workflows/ci-freebsd.yml index 4ea604883d0..6b815923f7a 100644 --- a/.github/workflows/ci-freebsd.yml +++ b/.github/workflows/ci-freebsd.yml @@ -113,6 +113,7 @@ jobs: devel/pkgconf \ ftp/curl \ graphics/libdrm \ + graphics/shaderc \ graphics/vulkan-headers \ graphics/vulkan-loader \ graphics/wayland \ diff --git a/.github/workflows/ci-linux.yml b/.github/workflows/ci-linux.yml index 19d4c239ef9..52601f60ca0 100644 --- a/.github/workflows/ci-linux.yml +++ b/.github/workflows/ci-linux.yml @@ -50,6 +50,7 @@ jobs: sudo add-apt-repository universe sudo apt-get install -y \ + glslang-tools \ libdrm-dev \ libfuse2 \ libgl-dev \ diff --git a/cmake/compile_definitions/linux.cmake b/cmake/compile_definitions/linux.cmake index c6b3e73dcdf..b3d0baf90fa 100644 --- a/cmake/compile_definitions/linux.cmake +++ b/cmake/compile_definitions/linux.cmake @@ -123,6 +123,14 @@ endif() # vulkan video encoding (via FFmpeg) if(${SUNSHINE_ENABLE_VULKAN}) find_package(Vulkan REQUIRED) + # prefer glslc, fall back to glslangValidator + find_package(Vulkan QUIET COMPONENTS glslc) + if(NOT TARGET Vulkan::glslc) + find_package(Vulkan QUIET COMPONENTS glslangValidator) + endif() + if(NOT TARGET Vulkan::glslc AND NOT TARGET Vulkan::glslangValidator) + message(FATAL_ERROR "Vulkan shader compiler not found (need glslc or glslangValidator)") + endif() endif() if(SUNSHINE_ENABLE_VULKAN AND Vulkan_FOUND) list(APPEND SUNSHINE_DEFINITIONS SUNSHINE_BUILD_VULKAN=1) @@ -131,6 +139,43 @@ if(SUNSHINE_ENABLE_VULKAN AND Vulkan_FOUND) list(APPEND PLATFORM_TARGET_FILES "${CMAKE_SOURCE_DIR}/src/platform/linux/vulkan_encode.h" "${CMAKE_SOURCE_DIR}/src/platform/linux/vulkan_encode.cpp") + + # compile GLSL -> SPIR-V -> C include at build time + set(VULKAN_SHADER_DIR "${CMAKE_BINARY_DIR}/generated-src/shaders") + set(VULKAN_SHADER_SOURCE "${SUNSHINE_SOURCE_ASSETS_DIR}/linux/assets/shaders/vulkan/rgb2yuv.comp") + set(VULKAN_SHADER_SPV "${VULKAN_SHADER_DIR}/rgb2yuv.spv") + set(VULKAN_SHADER_DATA "${VULKAN_SHADER_DIR}/rgb2yuv.spv.inc") + + file(MAKE_DIRECTORY "${VULKAN_SHADER_DIR}") + + if(TARGET Vulkan::glslc) + add_custom_command( + OUTPUT "${VULKAN_SHADER_SPV}" + COMMAND Vulkan::glslc -O "${VULKAN_SHADER_SOURCE}" -o "${VULKAN_SHADER_SPV}" + DEPENDS "${VULKAN_SHADER_SOURCE}" + COMMENT "Compiling Vulkan shader rgb2yuv.comp (glslc)" + VERBATIM) + else() + add_custom_command( + OUTPUT "${VULKAN_SHADER_SPV}" + COMMAND Vulkan::glslangValidator -V -o "${VULKAN_SHADER_SPV}" "${VULKAN_SHADER_SOURCE}" + DEPENDS "${VULKAN_SHADER_SOURCE}" + COMMENT "Compiling Vulkan shader rgb2yuv.comp (glslangValidator)" + VERBATIM) + endif() + + add_custom_command( + OUTPUT "${VULKAN_SHADER_DATA}" + COMMAND ${CMAKE_COMMAND} -DSPV_FILE=${VULKAN_SHADER_SPV} -DOUT_FILE=${VULKAN_SHADER_DATA} + -P "${CMAKE_SOURCE_DIR}/cmake/scripts/binary_to_c.cmake" + DEPENDS "${VULKAN_SHADER_SPV}" + COMMENT "Generating C include from rgb2yuv.spv" + VERBATIM) + + add_custom_target(vulkan_shaders + DEPENDS "${VULKAN_SHADER_DATA}" + COMMENT "Vulkan shader compilation") + set(SUNSHINE_TARGET_DEPENDENCIES ${SUNSHINE_TARGET_DEPENDENCIES} vulkan_shaders) endif() # wayland diff --git a/cmake/scripts/binary_to_c.cmake b/cmake/scripts/binary_to_c.cmake new file mode 100644 index 00000000000..e63f1dacdbc --- /dev/null +++ b/cmake/scripts/binary_to_c.cmake @@ -0,0 +1,33 @@ +# binary_to_c.cmake - Convert a binary file to a C uint32_t initializer list. +# Input: SPV_FILE - path to SPIR-V binary +# Output: OUT_FILE - path to write C initializer (e.g. {0x07230203, ...}) + +file(READ "${SPV_FILE}" _data HEX) +string(LENGTH "${_data}" _hex_len) +math(EXPR _num_bytes "${_hex_len} / 2") +math(EXPR _num_words "${_num_bytes} / 4") +math(EXPR _last "${_num_words} - 1") + +set(_out "{") +foreach(_idx RANGE 0 ${_last}) + math(EXPR _off "${_idx} * 8") + math(EXPR _off1 "${_off} + 2") + math(EXPR _off2 "${_off} + 4") + math(EXPR _off3 "${_off} + 6") + string(SUBSTRING "${_data}" ${_off} 2 _b0) + string(SUBSTRING "${_data}" ${_off1} 2 _b1) + string(SUBSTRING "${_data}" ${_off2} 2 _b2) + string(SUBSTRING "${_data}" ${_off3} 2 _b3) + # little-endian to uint32_t + string(APPEND _out "0x${_b3}${_b2}${_b1}${_b0}") + if(NOT _idx EQUAL _last) + string(APPEND _out ",") + endif() + math(EXPR _col "(${_idx} + 1) % 8") + if(_col EQUAL 0) + string(APPEND _out "\n") + endif() +endforeach() +string(APPEND _out "}\n") + +file(WRITE "${OUT_FILE}" "${_out}") diff --git a/packaging/linux/Arch/PKGBUILD b/packaging/linux/Arch/PKGBUILD index 0ecc1d781a2..03f5b17f922 100644 --- a/packaging/linux/Arch/PKGBUILD +++ b/packaging/linux/Arch/PKGBUILD @@ -66,6 +66,7 @@ makedepends=( 'npm' 'python-jinja' # required by the glad OpenGL/EGL loader generator 'python-setuptools' # required for glad OpenGL/EGL loader generated, v2.0.0 + 'shaderc' ) checkdepends=( diff --git a/packaging/linux/copr/Sunshine.spec b/packaging/linux/copr/Sunshine.spec index 055e8279b61..54f9d66a79b 100644 --- a/packaging/linux/copr/Sunshine.spec +++ b/packaging/linux/copr/Sunshine.spec @@ -41,6 +41,7 @@ BuildRequires: libXinerama-devel BuildRequires: libXrandr-devel BuildRequires: libXtst-devel BuildRequires: openssl-devel +BuildRequires: glslc BuildRequires: pipewire-devel BuildRequires: rpm-build BuildRequires: systemd-rpm-macros diff --git a/scripts/linux_build.sh b/scripts/linux_build.sh index c60cd4a5f79..41670fdf48f 100755 --- a/scripts/linux_build.sh +++ b/scripts/linux_build.sh @@ -194,6 +194,7 @@ function add_arch_deps() { 'opus' 'python-jinja' # glad OpenGL/EGL loader generator 'python-setuptools' # glad OpenGL/EGL loader generated, v2.0.0 + 'shaderc' 'udev' 'vulkan-headers' 'vulkan-icd-loader' @@ -252,6 +253,7 @@ function add_debian_based_deps() { "libxrandr-dev" # X11 "libxtst-dev" # X11 "libvulkan-dev" # Vulkan + "glslang-tools" # Vulkan shader compiler "ninja-build" "npm" # web-ui "python3-jinja2" # glad OpenGL/EGL loader generator @@ -337,6 +339,7 @@ function add_fedora_deps() { "rpm-build" # if you want to build an RPM binary package "vulkan-headers" "vulkan-loader-devel" + "glslc" "wget" # necessary for cuda install with `run` file "which" # necessary for cuda install with `run` file "xorg-x11-server-Xvfb" # necessary for headless unit testing diff --git a/src/platform/linux/shaders/rgb2yuv.spv b/src/platform/linux/shaders/rgb2yuv.spv deleted file mode 100644 index 6a76223f44db060f0feb95454168a90a5e166b8b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7820 zcmZvf3y{}U6~}+N~KzsP$VI)#n zfLgv9D@z2e47D;5XQ(vGS1+xxf~>LBo@!)`Q=iXo?-zgVcxTU?@A;l{&pp3;@A>`q z-`X;fI&jV)C@Mpi8_Ri!?%=&9)8)sUK>b;`R=>0Y*cVfRsQne2ppt5#L* z+mD#Nz=M$`eP^E|--nEVmm67Q?f&>#%pC)E>64i$c1-M7dpPTnb6(<{BiGsBtVGVj z66d;dK0`Qbl$+Mzh7|7P2FK>qalH-hHHAB^!3{0k{029yaA%=s@$@s%6A){ReGu58 z?LG}h4k-48XyYCFwO@&Et+r#2Ek3cagBo@-_E;Q=6&u@9Vzpn19bENdTZi$Zh%#;h zRa>`se~^3CiL_Ifd!(&@47PjGiIArDyAN{CHGUM@c+W+9bg}i1;~shkjEU%1%rj8> z*BVSs{cAY)IC5&Y7w(PN#&sZ`T_?8BCTG6URCXZR+Q*?g5r^}%$JbWB?HuooBmOS1 z&zg0-d#P(m!P;YCr=xv#)FK_IE=H-6HAbs&!z1>a=4zk-d5C|$7ii6*w&X?>^DdJ)3EIYZTEUM_6YPOvUx7{ zqnzShb8Y)!JxSerCENx$?}KtQajt7_htK;j825fR)*SLV{sSJ5o{Ozt{WfN~_8CYY zGMf`$fL>TQd50-3BGx@S6VX416+FYmg+o<6Jd3?>Hez3Thg{QjjD0_%@9WI97e9bF zUw#uYavwzGt-b!Rfd7q8ehDIH{o>Sc9@x69Gc|k&oEqHE)UXt+FEuO!J74}K@+QCf zMfSs*mLt~Wo*D1j)^`EgVSUD&kH}e{*nIB4w!AgWKwpH|KMS#^qc1MpV)n&7zNByy z(dQE5Jy=orwZv$zLcAODJ#fD3K92azmm;oZt~H2!@_eFjnR6L-_9=7L!pUdO~IyPoB?!ja z?u#`|L0^kllkXmD@(x~y$ZsLWv%S7>?zLz71+>F6)pr9T=NXE~}x+ zMX-H(BQlpL&*=!BMLx0KiR4pz$Ba9bIAgpg&T%bk_P*SNcwbHw#nmEVHd zeD&JUHzWELhxHkgzSsnIPbMSH-n<1{-)%gL`?494%f8$ScDOJ4wjgrui#Ye-JuGPc z4kY*By>RlY$vq7Ibg<_xpB|nMmUpB#`>^Fx!=mE127L<oPW6na(L0ngSd)c!kVC!|?>UT+rF*a+Q3pR)A8t?r2 zU4nMFhB4rPzP$A%zdH4O80`AiY`kk* z-#WCz`i%JqB4>T#+|`eQXA+klzYyDc)4LagfyfH&zBWnE4UZNURnz$AKAO~*yV8iRo#gFW^QBM)9i`b zJvGl97BtR%cCPznZ2Cu?*tsRvcZ2iH<34T0z5{WeyuqzmMqi zeXaci#C-CZdp|gHyTGaA0kFQ*@k6ll<$Kv-_u)ZA-gjZ-3~Ia&+jour`&oM^`e9@- z@({8a&iCCTh`f92eSZw?@V@JN6p{13i_?!k1)JY}PX3>P<(v6`jxBF~&px@->Ahco zUCaAmyz5xY6KIFE81pzHXD#A<1D^!1LslWq+l6*G&u`gIM9z8Q-2JD(&h;5q5bOE; z9+A&?>=^EgT;hC&xhaE1YM)8RrmeInQ3a zlD!=UKMd^s^|w$D+*t5>a67sKanFp~04JYs_(rgE<@4dIK>x$pH z^nDJIvo3LRT>~~3e|vIWiy?0=?_cJr(?i#T&FeE7Z%)_!GTKr10{8|*&UMAN^X$F{ zz67@3e8Ur?&Kfs?UB`8ecfMeeAn2C&Kk!23XyXSah~l-aGovw@oTu;uV#Pz z23}w4`z_e{@}6b#t5e@Dui*b`Hn*|vY4${&{#e9<#<|bVb-&Ud9bo&T9i9Go87#j6$+`a*EbmBv_#pD>kG*^_ zhWAw8AVkhH5+_$H*j%PduEB8f>5t4)=WYxEo7ZPE-kjczedHOgYfKv==epwDzrDfM zoBl|QI&16;HizpP?|j!7gU%Yp?1#v?hB(hQ5}apCf4mkh_p8|-qu}+WzR_Uk%X^l| zuTFjYgI(X6jdyM9I~<+*jA=*YtWTW&=m0nS<8|29oBlWeTdvt32V$rG^v5_j`Sizl zuw4416KpQ|^v49S>+9q1|NbvL7(&0I&%5DpU;Ta@T71p^=z^1vq(2UWbAC6{0x-9+ z?rHW!o&Hz~HqL!^uKQ(d8(e*d(24zQiQPqR=QZLmYMY-7S51SfCKa0g?{Tf-G)?xEQ7haf$0Tgi7A*z@u?j^{NBeK?$a{ttfxSWa=M zNL%H%=p+bZ%%9(YZvrRpJYvo5*>uC}vrg?Jz|NOXO-F*AI|ZGZ-VBycO-F&{6o;x= z)6o#dG;4Y*cJelBnhLKkH5~(XzP#)E`}jEUvB(bU_W$VP!FdOKMmdd%{(1j zUw$*s0Q=lE&o21e{Y31{P2ameGvW26wv)ilmruTTfUVhli8~c6Z(M#`zZ2|yeg4i; c{B7;C`8@i)%lS>J)}90J-B!QMPESSt2RCf@KmY&$ diff --git a/src/platform/linux/shaders/rgb2yuv.spv.h b/src/platform/linux/shaders/rgb2yuv.spv.h deleted file mode 100644 index 44c6724f8e0..00000000000 --- a/src/platform/linux/shaders/rgb2yuv.spv.h +++ /dev/null @@ -1,257 +0,0 @@ -/** - * @file src/platform/linux/shaders/rgb2yuv.spv.h - * @brief Pre-compiled SPIR-V for RGB to YUV compute shader (format-agnostic, supports NV12 and P010). - * @note Regenerate: glslc -O rgb2yuv.comp -o rgb2yuv.spv, then convert with this script. - */ -#pragma once -#include -#include - -static const std::array rgb2yuv_comp_spv = { - 0x07230203, 0x00010000, 0x000d000b, 0x00000293, 0x00000000, 0x00020011, 0x00000001, 0x00020011, - 0x00000032, 0x00020011, 0x00000038, 0x0006000b, 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, - 0x00000000, 0x0003000e, 0x00000000, 0x00000001, 0x0006000f, 0x00000005, 0x00000004, 0x6e69616d, - 0x00000000, 0x00000061, 0x00060010, 0x00000004, 0x00000011, 0x00000010, 0x00000010, 0x00000001, - 0x00030047, 0x00000015, 0x00000002, 0x00050048, 0x00000015, 0x00000000, 0x00000023, 0x00000000, - 0x00050048, 0x00000015, 0x00000001, 0x00000023, 0x00000010, 0x00050048, 0x00000015, 0x00000002, - 0x00000023, 0x00000020, 0x00050048, 0x00000015, 0x00000003, 0x00000023, 0x00000030, 0x00050048, - 0x00000015, 0x00000004, 0x00000023, 0x00000038, 0x00050048, 0x00000015, 0x00000005, 0x00000023, - 0x00000040, 0x00050048, 0x00000015, 0x00000006, 0x00000023, 0x00000048, 0x00050048, 0x00000015, - 0x00000007, 0x00000023, 0x00000050, 0x00050048, 0x00000015, 0x00000008, 0x00000023, 0x00000058, - 0x00050048, 0x00000015, 0x00000009, 0x00000023, 0x00000060, 0x00050048, 0x00000015, 0x0000000a, - 0x00000023, 0x00000068, 0x00040047, 0x00000045, 0x00000021, 0x00000003, 0x00040047, 0x00000045, - 0x00000022, 0x00000000, 0x00040047, 0x00000061, 0x0000000b, 0x0000001c, 0x00040047, 0x0000007b, - 0x00000021, 0x00000000, 0x00040047, 0x0000007b, 0x00000022, 0x00000000, 0x00030047, 0x000000bf, - 0x00000019, 0x00040047, 0x000000bf, 0x00000021, 0x00000001, 0x00040047, 0x000000bf, 0x00000022, - 0x00000000, 0x00030047, 0x0000013a, 0x00000019, 0x00040047, 0x0000013a, 0x00000021, 0x00000002, - 0x00040047, 0x0000013a, 0x00000022, 0x00000000, 0x00040047, 0x00000150, 0x0000000b, 0x00000019, - 0x00020013, 0x00000002, 0x00030021, 0x00000003, 0x00000002, 0x00030016, 0x00000006, 0x00000020, - 0x00040017, 0x00000007, 0x00000006, 0x00000003, 0x00040015, 0x00000009, 0x00000020, 0x00000001, - 0x00040017, 0x0000000a, 0x00000009, 0x00000002, 0x00040017, 0x00000013, 0x00000006, 0x00000004, - 0x00040017, 0x00000014, 0x00000006, 0x00000002, 0x000d001e, 0x00000015, 0x00000013, 0x00000013, - 0x00000013, 0x00000014, 0x00000014, 0x0000000a, 0x0000000a, 0x0000000a, 0x0000000a, 0x0000000a, - 0x00000009, 0x00040020, 0x00000016, 0x00000009, 0x00000015, 0x0004003b, 0x00000016, 0x00000017, - 0x00000009, 0x0004002b, 0x00000009, 0x00000018, 0x00000008, 0x00040020, 0x00000019, 0x00000009, - 0x0000000a, 0x00020014, 0x0000001d, 0x00040015, 0x0000001e, 0x00000020, 0x00000000, 0x0004002b, - 0x0000001e, 0x0000001f, 0x00000000, 0x0004002b, 0x00000009, 0x00000023, 0x00000000, 0x0004002b, - 0x0000001e, 0x00000027, 0x00000001, 0x0004002b, 0x00000009, 0x00000030, 0x00000009, 0x00040020, - 0x00000031, 0x00000009, 0x00000009, 0x00090019, 0x00000042, 0x00000006, 0x00000001, 0x00000000, - 0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x0003001b, 0x00000043, 0x00000042, 0x00040020, - 0x00000044, 0x00000000, 0x00000043, 0x0004003b, 0x00000044, 0x00000045, 0x00000000, 0x0004002b, - 0x00000006, 0x00000049, 0x3f000000, 0x0004002b, 0x00000006, 0x00000050, 0x00000000, 0x0004002b, - 0x0000001e, 0x00000055, 0x00000003, 0x00040017, 0x0000005f, 0x0000001e, 0x00000003, 0x00040020, - 0x00000060, 0x00000001, 0x0000005f, 0x0004003b, 0x00000060, 0x00000061, 0x00000001, 0x00040017, - 0x00000062, 0x0000001e, 0x00000002, 0x0004002b, 0x00000009, 0x00000068, 0x00000007, 0x0004002b, - 0x00000006, 0x0000007a, 0x3f800000, 0x0004003b, 0x00000044, 0x0000007b, 0x00000000, 0x0004002b, - 0x00000009, 0x00000083, 0x00000006, 0x0004002b, 0x00000009, 0x0000008c, 0x00000005, 0x0004002b, - 0x00000009, 0x00000099, 0x0000000a, 0x00040020, 0x000000b3, 0x00000009, 0x00000013, 0x00040020, - 0x000000b9, 0x00000009, 0x00000006, 0x00090019, 0x000000bd, 0x00000006, 0x00000001, 0x00000000, - 0x00000000, 0x00000000, 0x00000002, 0x00000000, 0x00040020, 0x000000be, 0x00000000, 0x000000bd, - 0x0004003b, 0x000000be, 0x000000bf, 0x00000000, 0x0004002b, 0x00000009, 0x000000c3, 0x00000003, - 0x0004002b, 0x00000009, 0x000000cd, 0x00000001, 0x0005002c, 0x0000000a, 0x00000109, 0x000000cd, - 0x00000023, 0x0005002c, 0x0000000a, 0x00000110, 0x00000023, 0x000000cd, 0x0005002c, 0x0000000a, - 0x00000117, 0x000000cd, 0x000000cd, 0x0004002b, 0x00000006, 0x00000125, 0x3e800000, 0x0004002b, - 0x00000009, 0x00000131, 0x00000002, 0x0004003b, 0x000000be, 0x0000013a, 0x00000000, 0x0004002b, - 0x00000009, 0x00000140, 0x00000004, 0x0004002b, 0x0000001e, 0x0000014f, 0x00000010, 0x0006002c, - 0x0000005f, 0x00000150, 0x0000014f, 0x0000014f, 0x00000027, 0x0005002c, 0x00000014, 0x00000291, - 0x0000007a, 0x0000007a, 0x0005002c, 0x00000014, 0x00000292, 0x00000049, 0x00000049, 0x00050036, - 0x00000002, 0x00000004, 0x00000000, 0x00000003, 0x000200f8, 0x00000005, 0x000300f7, 0x00000151, - 0x00000000, 0x000300fb, 0x0000001f, 0x00000152, 0x000200f8, 0x00000152, 0x0004003d, 0x0000005f, - 0x00000063, 0x00000061, 0x0007004f, 0x00000062, 0x00000064, 0x00000063, 0x00000063, 0x00000000, - 0x00000001, 0x0004007c, 0x0000000a, 0x00000065, 0x00000064, 0x00050051, 0x00000009, 0x00000067, - 0x00000065, 0x00000000, 0x00060041, 0x00000031, 0x00000069, 0x00000017, 0x00000068, 0x0000001f, - 0x0004003d, 0x00000009, 0x0000006a, 0x00000069, 0x000500af, 0x0000001d, 0x0000006b, 0x00000067, - 0x0000006a, 0x000400a8, 0x0000001d, 0x0000006c, 0x0000006b, 0x000300f7, 0x0000006e, 0x00000000, - 0x000400fa, 0x0000006c, 0x0000006d, 0x0000006e, 0x000200f8, 0x0000006d, 0x00050051, 0x00000009, - 0x00000070, 0x00000065, 0x00000001, 0x00060041, 0x00000031, 0x00000071, 0x00000017, 0x00000068, - 0x00000027, 0x0004003d, 0x00000009, 0x00000072, 0x00000071, 0x000500af, 0x0000001d, 0x00000073, - 0x00000070, 0x00000072, 0x000200f9, 0x0000006e, 0x000200f8, 0x0000006e, 0x000700f5, 0x0000001d, - 0x00000074, 0x0000006b, 0x00000152, 0x00000073, 0x0000006d, 0x000300f7, 0x00000076, 0x00000000, - 0x000400fa, 0x00000074, 0x00000075, 0x00000076, 0x000200f8, 0x00000075, 0x000200f9, 0x00000151, - 0x000200f8, 0x00000076, 0x0004003d, 0x00000043, 0x0000007c, 0x0000007b, 0x00040064, 0x00000042, - 0x0000007d, 0x0000007c, 0x00050067, 0x0000000a, 0x0000007e, 0x0000007d, 0x00000023, 0x0004006f, - 0x00000014, 0x0000007f, 0x0000007e, 0x00050088, 0x00000014, 0x00000081, 0x00000291, 0x0000007f, - 0x00050041, 0x00000019, 0x00000084, 0x00000017, 0x00000083, 0x0004003d, 0x0000000a, 0x00000085, - 0x00000084, 0x0004006f, 0x00000014, 0x00000086, 0x00000085, 0x00050041, 0x00000019, 0x00000087, - 0x00000017, 0x00000068, 0x0004003d, 0x0000000a, 0x00000088, 0x00000087, 0x0004006f, 0x00000014, - 0x00000089, 0x00000088, 0x00050088, 0x00000014, 0x0000008a, 0x00000086, 0x00000089, 0x00050041, - 0x00000019, 0x0000008d, 0x00000017, 0x0000008c, 0x0004003d, 0x0000000a, 0x0000008e, 0x0000008d, - 0x0004006f, 0x00000014, 0x0000008f, 0x0000008e, 0x0004006f, 0x00000014, 0x00000091, 0x00000065, - 0x00050081, 0x00000014, 0x00000093, 0x00000091, 0x00000292, 0x00050085, 0x00000014, 0x00000095, - 0x00000093, 0x0000008a, 0x00050081, 0x00000014, 0x00000096, 0x0000008f, 0x00000095, 0x00050085, - 0x00000014, 0x00000098, 0x00000096, 0x00000081, 0x00050041, 0x00000031, 0x0000009a, 0x00000017, - 0x00000099, 0x0004003d, 0x00000009, 0x0000009b, 0x0000009a, 0x000500ab, 0x0000001d, 0x0000009c, - 0x0000009b, 0x00000023, 0x000300f7, 0x0000009e, 0x00000000, 0x000400fa, 0x0000009c, 0x0000009d, - 0x0000009e, 0x000200f8, 0x0000009d, 0x00050051, 0x00000006, 0x000000a0, 0x00000098, 0x00000001, - 0x00050083, 0x00000006, 0x000000a1, 0x0000007a, 0x000000a0, 0x00060052, 0x00000014, 0x0000022f, - 0x000000a1, 0x00000098, 0x00000001, 0x000200f9, 0x0000009e, 0x000200f8, 0x0000009e, 0x000700f5, - 0x00000014, 0x0000024d, 0x00000098, 0x00000076, 0x0000022f, 0x0000009d, 0x0004003d, 0x00000043, - 0x000000a4, 0x0000007b, 0x00070058, 0x00000013, 0x000000a6, 0x000000a4, 0x0000024d, 0x00000002, - 0x00000050, 0x0008004f, 0x00000007, 0x000000a7, 0x000000a6, 0x000000a6, 0x00000000, 0x00000001, - 0x00000002, 0x00060041, 0x00000031, 0x000000a8, 0x00000017, 0x00000030, 0x0000001f, 0x0004003d, - 0x00000009, 0x000000a9, 0x000000a8, 0x000500ad, 0x0000001d, 0x000000aa, 0x000000a9, 0x00000023, - 0x000300f7, 0x000000ac, 0x00000000, 0x000400fa, 0x000000aa, 0x000000ab, 0x000000ac, 0x000200f8, - 0x000000ab, 0x00050041, 0x00000019, 0x0000015c, 0x00000017, 0x00000018, 0x0004003d, 0x0000000a, - 0x0000015d, 0x0000015c, 0x00050082, 0x0000000a, 0x0000015e, 0x00000065, 0x0000015d, 0x00050051, - 0x00000009, 0x00000160, 0x0000015e, 0x00000000, 0x000500af, 0x0000001d, 0x00000161, 0x00000160, - 0x00000023, 0x000300f7, 0x00000166, 0x00000000, 0x000400fa, 0x00000161, 0x00000162, 0x00000166, - 0x000200f8, 0x00000162, 0x00050051, 0x00000009, 0x00000164, 0x0000015e, 0x00000001, 0x000500af, - 0x0000001d, 0x00000165, 0x00000164, 0x00000023, 0x000200f9, 0x00000166, 0x000200f8, 0x00000166, - 0x000700f5, 0x0000001d, 0x00000167, 0x00000161, 0x000000ab, 0x00000165, 0x00000162, 0x000300f7, - 0x0000016e, 0x00000000, 0x000400fa, 0x00000167, 0x00000168, 0x0000016e, 0x000200f8, 0x00000168, - 0x000500b1, 0x0000001d, 0x0000016d, 0x00000160, 0x000000a9, 0x000200f9, 0x0000016e, 0x000200f8, - 0x0000016e, 0x000700f5, 0x0000001d, 0x0000016f, 0x00000167, 0x00000166, 0x0000016d, 0x00000168, - 0x000300f7, 0x00000176, 0x00000000, 0x000400fa, 0x0000016f, 0x00000170, 0x00000176, 0x000200f8, - 0x00000170, 0x00050051, 0x00000009, 0x00000172, 0x0000015e, 0x00000001, 0x00060041, 0x00000031, - 0x00000173, 0x00000017, 0x00000030, 0x00000027, 0x0004003d, 0x00000009, 0x00000174, 0x00000173, - 0x000500b1, 0x0000001d, 0x00000175, 0x00000172, 0x00000174, 0x000200f9, 0x00000176, 0x000200f8, - 0x00000176, 0x000700f5, 0x0000001d, 0x00000177, 0x0000016f, 0x0000016e, 0x00000175, 0x00000170, - 0x000300f7, 0x0000018a, 0x00000000, 0x000400fa, 0x00000177, 0x00000178, 0x0000018a, 0x000200f8, - 0x00000178, 0x0004003d, 0x00000043, 0x00000179, 0x00000045, 0x0004006f, 0x00000014, 0x0000017b, - 0x0000015e, 0x00050081, 0x00000014, 0x0000017d, 0x0000017b, 0x00000292, 0x00050041, 0x00000019, - 0x0000017e, 0x00000017, 0x00000030, 0x0004003d, 0x0000000a, 0x0000017f, 0x0000017e, 0x0004006f, - 0x00000014, 0x00000180, 0x0000017f, 0x00050088, 0x00000014, 0x00000181, 0x0000017d, 0x00000180, - 0x00070058, 0x00000013, 0x00000182, 0x00000179, 0x00000181, 0x00000002, 0x00000050, 0x0008004f, - 0x00000007, 0x00000185, 0x00000182, 0x00000182, 0x00000002, 0x00000001, 0x00000000, 0x00050051, - 0x00000006, 0x00000187, 0x00000182, 0x00000003, 0x00060050, 0x00000007, 0x00000188, 0x00000187, - 0x00000187, 0x00000187, 0x0008000c, 0x00000007, 0x00000189, 0x00000001, 0x0000002e, 0x000000a7, - 0x00000185, 0x00000188, 0x000200f9, 0x0000018a, 0x000200f8, 0x0000018a, 0x000700f5, 0x00000007, - 0x00000251, 0x000000a7, 0x00000176, 0x00000189, 0x00000178, 0x000200f9, 0x000000ac, 0x000200f8, - 0x000000ac, 0x000700f5, 0x00000007, 0x00000252, 0x000000a7, 0x0000009e, 0x00000251, 0x0000018a, - 0x00050041, 0x000000b3, 0x000000b4, 0x00000017, 0x00000023, 0x0004003d, 0x00000013, 0x000000b5, - 0x000000b4, 0x0008004f, 0x00000007, 0x000000b6, 0x000000b5, 0x000000b5, 0x00000000, 0x00000001, - 0x00000002, 0x00050094, 0x00000006, 0x000000b8, 0x000000b6, 0x00000252, 0x00060041, 0x000000b9, - 0x000000ba, 0x00000017, 0x00000023, 0x00000055, 0x0004003d, 0x00000006, 0x000000bb, 0x000000ba, - 0x00050081, 0x00000006, 0x000000bc, 0x000000b8, 0x000000bb, 0x0004003d, 0x000000bd, 0x000000c0, - 0x000000bf, 0x00060041, 0x000000b9, 0x000000c4, 0x00000017, 0x000000c3, 0x0000001f, 0x0004003d, - 0x00000006, 0x000000c5, 0x000000c4, 0x00050085, 0x00000006, 0x000000c6, 0x000000bc, 0x000000c5, - 0x00060041, 0x000000b9, 0x000000c7, 0x00000017, 0x000000c3, 0x00000027, 0x0004003d, 0x00000006, - 0x000000c8, 0x000000c7, 0x00050081, 0x00000006, 0x000000c9, 0x000000c6, 0x000000c8, 0x00070050, - 0x00000013, 0x000000ca, 0x000000c9, 0x00000050, 0x00000050, 0x00000050, 0x00040063, 0x000000c0, - 0x00000065, 0x000000ca, 0x000500c7, 0x00000009, 0x000000ce, 0x00000067, 0x000000cd, 0x000500aa, - 0x0000001d, 0x000000cf, 0x000000ce, 0x00000023, 0x000300f7, 0x000000d1, 0x00000000, 0x000400fa, - 0x000000cf, 0x000000d0, 0x000000d1, 0x000200f8, 0x000000d0, 0x00050051, 0x00000009, 0x000000d3, - 0x00000065, 0x00000001, 0x000500c7, 0x00000009, 0x000000d4, 0x000000d3, 0x000000cd, 0x000500aa, - 0x0000001d, 0x000000d5, 0x000000d4, 0x00000023, 0x000200f9, 0x000000d1, 0x000200f8, 0x000000d1, - 0x000700f5, 0x0000001d, 0x000000d6, 0x000000cf, 0x000000ac, 0x000000d5, 0x000000d0, 0x000300f7, - 0x000000d8, 0x00000000, 0x000400fa, 0x000000d6, 0x000000d7, 0x000000d8, 0x000200f8, 0x000000d7, - 0x00050085, 0x00000014, 0x000000dc, 0x0000008a, 0x00000081, 0x000300f7, 0x000000e1, 0x00000000, - 0x000400fa, 0x0000009c, 0x000000e0, 0x000000e1, 0x000200f8, 0x000000e0, 0x00050051, 0x00000006, - 0x000000e3, 0x000000dc, 0x00000001, 0x0004007f, 0x00000006, 0x000000e4, 0x000000e3, 0x00060052, - 0x00000014, 0x00000239, 0x000000e4, 0x000000dc, 0x00000001, 0x000200f9, 0x000000e1, 0x000200f8, - 0x000000e1, 0x000700f5, 0x00000014, 0x0000025a, 0x000000dc, 0x000000d7, 0x00000239, 0x000000e0, - 0x0004003d, 0x00000043, 0x000000e7, 0x0000007b, 0x00050051, 0x00000006, 0x000000ea, 0x0000025a, - 0x00000000, 0x00050050, 0x00000014, 0x000000eb, 0x000000ea, 0x00000050, 0x00050081, 0x00000014, - 0x000000ec, 0x0000024d, 0x000000eb, 0x00070058, 0x00000013, 0x000000ed, 0x000000e7, 0x000000ec, - 0x00000002, 0x00000050, 0x0008004f, 0x00000007, 0x000000ee, 0x000000ed, 0x000000ed, 0x00000000, - 0x00000001, 0x00000002, 0x0004003d, 0x00000043, 0x000000f0, 0x0000007b, 0x00050051, 0x00000006, - 0x000000f3, 0x0000025a, 0x00000001, 0x00050050, 0x00000014, 0x000000f4, 0x00000050, 0x000000f3, - 0x00050081, 0x00000014, 0x000000f5, 0x0000024d, 0x000000f4, 0x00070058, 0x00000013, 0x000000f6, - 0x000000f0, 0x000000f5, 0x00000002, 0x00000050, 0x0008004f, 0x00000007, 0x000000f7, 0x000000f6, - 0x000000f6, 0x00000000, 0x00000001, 0x00000002, 0x0004003d, 0x00000043, 0x000000f9, 0x0000007b, - 0x00050081, 0x00000014, 0x00000100, 0x0000024d, 0x0000025a, 0x00070058, 0x00000013, 0x00000101, - 0x000000f9, 0x00000100, 0x00000002, 0x00000050, 0x0008004f, 0x00000007, 0x00000102, 0x00000101, - 0x00000101, 0x00000000, 0x00000001, 0x00000002, 0x000300f7, 0x00000107, 0x00000000, 0x000400fa, - 0x000000aa, 0x00000106, 0x00000107, 0x000200f8, 0x00000106, 0x00050080, 0x0000000a, 0x0000010a, - 0x00000065, 0x00000109, 0x00050041, 0x00000019, 0x00000191, 0x00000017, 0x00000018, 0x0004003d, - 0x0000000a, 0x00000192, 0x00000191, 0x00050082, 0x0000000a, 0x00000193, 0x0000010a, 0x00000192, - 0x00050051, 0x00000009, 0x00000195, 0x00000193, 0x00000000, 0x000500af, 0x0000001d, 0x00000196, - 0x00000195, 0x00000023, 0x000300f7, 0x0000019b, 0x00000000, 0x000400fa, 0x00000196, 0x00000197, - 0x0000019b, 0x000200f8, 0x00000197, 0x00050051, 0x00000009, 0x00000199, 0x00000193, 0x00000001, - 0x000500af, 0x0000001d, 0x0000019a, 0x00000199, 0x00000023, 0x000200f9, 0x0000019b, 0x000200f8, - 0x0000019b, 0x000700f5, 0x0000001d, 0x0000019c, 0x00000196, 0x00000106, 0x0000019a, 0x00000197, - 0x000300f7, 0x000001a3, 0x00000000, 0x000400fa, 0x0000019c, 0x0000019d, 0x000001a3, 0x000200f8, - 0x0000019d, 0x000500b1, 0x0000001d, 0x000001a2, 0x00000195, 0x000000a9, 0x000200f9, 0x000001a3, - 0x000200f8, 0x000001a3, 0x000700f5, 0x0000001d, 0x000001a4, 0x0000019c, 0x0000019b, 0x000001a2, - 0x0000019d, 0x000300f7, 0x000001ab, 0x00000000, 0x000400fa, 0x000001a4, 0x000001a5, 0x000001ab, - 0x000200f8, 0x000001a5, 0x00050051, 0x00000009, 0x000001a7, 0x00000193, 0x00000001, 0x00060041, - 0x00000031, 0x000001a8, 0x00000017, 0x00000030, 0x00000027, 0x0004003d, 0x00000009, 0x000001a9, - 0x000001a8, 0x000500b1, 0x0000001d, 0x000001aa, 0x000001a7, 0x000001a9, 0x000200f9, 0x000001ab, - 0x000200f8, 0x000001ab, 0x000700f5, 0x0000001d, 0x000001ac, 0x000001a4, 0x000001a3, 0x000001aa, - 0x000001a5, 0x000300f7, 0x000001bf, 0x00000000, 0x000400fa, 0x000001ac, 0x000001ad, 0x000001bf, - 0x000200f8, 0x000001ad, 0x0004003d, 0x00000043, 0x000001ae, 0x00000045, 0x0004006f, 0x00000014, - 0x000001b0, 0x00000193, 0x00050081, 0x00000014, 0x000001b2, 0x000001b0, 0x00000292, 0x00050041, - 0x00000019, 0x000001b3, 0x00000017, 0x00000030, 0x0004003d, 0x0000000a, 0x000001b4, 0x000001b3, - 0x0004006f, 0x00000014, 0x000001b5, 0x000001b4, 0x00050088, 0x00000014, 0x000001b6, 0x000001b2, - 0x000001b5, 0x00070058, 0x00000013, 0x000001b7, 0x000001ae, 0x000001b6, 0x00000002, 0x00000050, - 0x0008004f, 0x00000007, 0x000001ba, 0x000001b7, 0x000001b7, 0x00000002, 0x00000001, 0x00000000, - 0x00050051, 0x00000006, 0x000001bc, 0x000001b7, 0x00000003, 0x00060050, 0x00000007, 0x000001bd, - 0x000001bc, 0x000001bc, 0x000001bc, 0x0008000c, 0x00000007, 0x000001be, 0x00000001, 0x0000002e, - 0x000000ee, 0x000001ba, 0x000001bd, 0x000200f9, 0x000001bf, 0x000200f8, 0x000001bf, 0x000700f5, - 0x00000007, 0x0000025e, 0x000000ee, 0x000001ab, 0x000001be, 0x000001ad, 0x00050080, 0x0000000a, - 0x00000111, 0x00000065, 0x00000110, 0x00050082, 0x0000000a, 0x000001c8, 0x00000111, 0x00000192, - 0x00050051, 0x00000009, 0x000001ca, 0x000001c8, 0x00000000, 0x000500af, 0x0000001d, 0x000001cb, - 0x000001ca, 0x00000023, 0x000300f7, 0x000001d0, 0x00000000, 0x000400fa, 0x000001cb, 0x000001cc, - 0x000001d0, 0x000200f8, 0x000001cc, 0x00050051, 0x00000009, 0x000001ce, 0x000001c8, 0x00000001, - 0x000500af, 0x0000001d, 0x000001cf, 0x000001ce, 0x00000023, 0x000200f9, 0x000001d0, 0x000200f8, - 0x000001d0, 0x000700f5, 0x0000001d, 0x000001d1, 0x000001cb, 0x000001bf, 0x000001cf, 0x000001cc, - 0x000300f7, 0x000001d8, 0x00000000, 0x000400fa, 0x000001d1, 0x000001d2, 0x000001d8, 0x000200f8, - 0x000001d2, 0x000500b1, 0x0000001d, 0x000001d7, 0x000001ca, 0x000000a9, 0x000200f9, 0x000001d8, - 0x000200f8, 0x000001d8, 0x000700f5, 0x0000001d, 0x000001d9, 0x000001d1, 0x000001d0, 0x000001d7, - 0x000001d2, 0x000300f7, 0x000001e0, 0x00000000, 0x000400fa, 0x000001d9, 0x000001da, 0x000001e0, - 0x000200f8, 0x000001da, 0x00050051, 0x00000009, 0x000001dc, 0x000001c8, 0x00000001, 0x00060041, - 0x00000031, 0x000001dd, 0x00000017, 0x00000030, 0x00000027, 0x0004003d, 0x00000009, 0x000001de, - 0x000001dd, 0x000500b1, 0x0000001d, 0x000001df, 0x000001dc, 0x000001de, 0x000200f9, 0x000001e0, - 0x000200f8, 0x000001e0, 0x000700f5, 0x0000001d, 0x000001e1, 0x000001d9, 0x000001d8, 0x000001df, - 0x000001da, 0x000300f7, 0x000001f4, 0x00000000, 0x000400fa, 0x000001e1, 0x000001e2, 0x000001f4, - 0x000200f8, 0x000001e2, 0x0004003d, 0x00000043, 0x000001e3, 0x00000045, 0x0004006f, 0x00000014, - 0x000001e5, 0x000001c8, 0x00050081, 0x00000014, 0x000001e7, 0x000001e5, 0x00000292, 0x00050041, - 0x00000019, 0x000001e8, 0x00000017, 0x00000030, 0x0004003d, 0x0000000a, 0x000001e9, 0x000001e8, - 0x0004006f, 0x00000014, 0x000001ea, 0x000001e9, 0x00050088, 0x00000014, 0x000001eb, 0x000001e7, - 0x000001ea, 0x00070058, 0x00000013, 0x000001ec, 0x000001e3, 0x000001eb, 0x00000002, 0x00000050, - 0x0008004f, 0x00000007, 0x000001ef, 0x000001ec, 0x000001ec, 0x00000002, 0x00000001, 0x00000000, - 0x00050051, 0x00000006, 0x000001f1, 0x000001ec, 0x00000003, 0x00060050, 0x00000007, 0x000001f2, - 0x000001f1, 0x000001f1, 0x000001f1, 0x0008000c, 0x00000007, 0x000001f3, 0x00000001, 0x0000002e, - 0x000000f7, 0x000001ef, 0x000001f2, 0x000200f9, 0x000001f4, 0x000200f8, 0x000001f4, 0x000700f5, - 0x00000007, 0x00000266, 0x000000f7, 0x000001e0, 0x000001f3, 0x000001e2, 0x00050080, 0x0000000a, - 0x00000118, 0x00000065, 0x00000117, 0x00050082, 0x0000000a, 0x000001fd, 0x00000118, 0x00000192, - 0x00050051, 0x00000009, 0x000001ff, 0x000001fd, 0x00000000, 0x000500af, 0x0000001d, 0x00000200, - 0x000001ff, 0x00000023, 0x000300f7, 0x00000205, 0x00000000, 0x000400fa, 0x00000200, 0x00000201, - 0x00000205, 0x000200f8, 0x00000201, 0x00050051, 0x00000009, 0x00000203, 0x000001fd, 0x00000001, - 0x000500af, 0x0000001d, 0x00000204, 0x00000203, 0x00000023, 0x000200f9, 0x00000205, 0x000200f8, - 0x00000205, 0x000700f5, 0x0000001d, 0x00000206, 0x00000200, 0x000001f4, 0x00000204, 0x00000201, - 0x000300f7, 0x0000020d, 0x00000000, 0x000400fa, 0x00000206, 0x00000207, 0x0000020d, 0x000200f8, - 0x00000207, 0x000500b1, 0x0000001d, 0x0000020c, 0x000001ff, 0x000000a9, 0x000200f9, 0x0000020d, - 0x000200f8, 0x0000020d, 0x000700f5, 0x0000001d, 0x0000020e, 0x00000206, 0x00000205, 0x0000020c, - 0x00000207, 0x000300f7, 0x00000215, 0x00000000, 0x000400fa, 0x0000020e, 0x0000020f, 0x00000215, - 0x000200f8, 0x0000020f, 0x00050051, 0x00000009, 0x00000211, 0x000001fd, 0x00000001, 0x00060041, - 0x00000031, 0x00000212, 0x00000017, 0x00000030, 0x00000027, 0x0004003d, 0x00000009, 0x00000213, - 0x00000212, 0x000500b1, 0x0000001d, 0x00000214, 0x00000211, 0x00000213, 0x000200f9, 0x00000215, - 0x000200f8, 0x00000215, 0x000700f5, 0x0000001d, 0x00000216, 0x0000020e, 0x0000020d, 0x00000214, - 0x0000020f, 0x000300f7, 0x00000229, 0x00000000, 0x000400fa, 0x00000216, 0x00000217, 0x00000229, - 0x000200f8, 0x00000217, 0x0004003d, 0x00000043, 0x00000218, 0x00000045, 0x0004006f, 0x00000014, - 0x0000021a, 0x000001fd, 0x00050081, 0x00000014, 0x0000021c, 0x0000021a, 0x00000292, 0x00050041, - 0x00000019, 0x0000021d, 0x00000017, 0x00000030, 0x0004003d, 0x0000000a, 0x0000021e, 0x0000021d, - 0x0004006f, 0x00000014, 0x0000021f, 0x0000021e, 0x00050088, 0x00000014, 0x00000220, 0x0000021c, - 0x0000021f, 0x00070058, 0x00000013, 0x00000221, 0x00000218, 0x00000220, 0x00000002, 0x00000050, - 0x0008004f, 0x00000007, 0x00000224, 0x00000221, 0x00000221, 0x00000002, 0x00000001, 0x00000000, - 0x00050051, 0x00000006, 0x00000226, 0x00000221, 0x00000003, 0x00060050, 0x00000007, 0x00000227, - 0x00000226, 0x00000226, 0x00000226, 0x0008000c, 0x00000007, 0x00000228, 0x00000001, 0x0000002e, - 0x00000102, 0x00000224, 0x00000227, 0x000200f9, 0x00000229, 0x000200f8, 0x00000229, 0x000700f5, - 0x00000007, 0x00000272, 0x00000102, 0x00000215, 0x00000228, 0x00000217, 0x000200f9, 0x00000107, - 0x000200f8, 0x00000107, 0x000700f5, 0x00000007, 0x00000290, 0x00000102, 0x000000e1, 0x00000272, - 0x00000229, 0x000700f5, 0x00000007, 0x0000028b, 0x000000f7, 0x000000e1, 0x00000266, 0x00000229, - 0x000700f5, 0x00000007, 0x00000282, 0x000000ee, 0x000000e1, 0x0000025e, 0x00000229, 0x00050081, - 0x00000007, 0x00000120, 0x00000252, 0x00000282, 0x00050081, 0x00000007, 0x00000122, 0x00000120, - 0x0000028b, 0x00050081, 0x00000007, 0x00000124, 0x00000122, 0x00000290, 0x0005008e, 0x00000007, - 0x00000126, 0x00000124, 0x00000125, 0x00050041, 0x000000b3, 0x00000128, 0x00000017, 0x000000cd, - 0x0004003d, 0x00000013, 0x00000129, 0x00000128, 0x0008004f, 0x00000007, 0x0000012a, 0x00000129, - 0x00000129, 0x00000000, 0x00000001, 0x00000002, 0x00050094, 0x00000006, 0x0000012c, 0x0000012a, - 0x00000126, 0x00060041, 0x000000b9, 0x0000012d, 0x00000017, 0x000000cd, 0x00000055, 0x0004003d, - 0x00000006, 0x0000012e, 0x0000012d, 0x00050081, 0x00000006, 0x0000012f, 0x0000012c, 0x0000012e, - 0x00050041, 0x000000b3, 0x00000132, 0x00000017, 0x00000131, 0x0004003d, 0x00000013, 0x00000133, - 0x00000132, 0x0008004f, 0x00000007, 0x00000134, 0x00000133, 0x00000133, 0x00000000, 0x00000001, - 0x00000002, 0x00050094, 0x00000006, 0x00000136, 0x00000134, 0x00000126, 0x00060041, 0x000000b9, - 0x00000137, 0x00000017, 0x00000131, 0x00000055, 0x0004003d, 0x00000006, 0x00000138, 0x00000137, - 0x00050081, 0x00000006, 0x00000139, 0x00000136, 0x00000138, 0x0004003d, 0x000000bd, 0x0000013b, - 0x0000013a, 0x000500c3, 0x0000000a, 0x0000013e, 0x00000065, 0x00000117, 0x00060041, 0x000000b9, - 0x00000141, 0x00000017, 0x00000140, 0x0000001f, 0x0004003d, 0x00000006, 0x00000142, 0x00000141, - 0x00050085, 0x00000006, 0x00000143, 0x0000012f, 0x00000142, 0x00060041, 0x000000b9, 0x00000144, - 0x00000017, 0x00000140, 0x00000027, 0x0004003d, 0x00000006, 0x00000145, 0x00000144, 0x00050081, - 0x00000006, 0x00000146, 0x00000143, 0x00000145, 0x00050085, 0x00000006, 0x0000014a, 0x00000139, - 0x00000142, 0x00050081, 0x00000006, 0x0000014d, 0x0000014a, 0x00000145, 0x00070050, 0x00000013, - 0x0000014e, 0x00000146, 0x0000014d, 0x00000050, 0x00000050, 0x00040063, 0x0000013b, 0x0000013e, - 0x0000014e, 0x000200f9, 0x000000d8, 0x000200f8, 0x000000d8, 0x000200f9, 0x00000151, 0x000200f8, - 0x00000151, 0x000100fd, 0x00010038, -}; -static const size_t rgb2yuv_comp_spv_size = rgb2yuv_comp_spv.size() * sizeof(uint32_t); diff --git a/src/platform/linux/vulkan_encode.cpp b/src/platform/linux/vulkan_encode.cpp index bb2ec72346a..25d532056a0 100644 --- a/src/platform/linux/vulkan_encode.cpp +++ b/src/platform/linux/vulkan_encode.cpp @@ -4,6 +4,7 @@ * No EGL/GL dependency — all GPU work stays in a single Vulkan queue. */ #include +#include #include #include #include @@ -16,12 +17,17 @@ extern "C" { } #include "graphics.h" -#include "shaders/rgb2yuv.spv.h" #include "src/config.h" #include "src/logging.h" #include "src/video_colorspace.h" #include "vulkan_encode.h" +// SPIR-V data generated at build time +static const std::vector rgb2yuv_comp_spv_data +#include "shaders/rgb2yuv.spv.inc" + ; +static const size_t rgb2yuv_comp_spv_size = rgb2yuv_comp_spv_data.size() * sizeof(uint32_t); + #include using namespace std::literals; @@ -294,7 +300,7 @@ namespace vk { // Shader module VkShaderModuleCreateInfo shader_ci = {VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; shader_ci.codeSize = rgb2yuv_comp_spv_size; - shader_ci.pCode = rgb2yuv_comp_spv.data(); + shader_ci.pCode = rgb2yuv_comp_spv_data.data(); VK_CHECK_BOOL(vkCreateShaderModule(vk_dev.dev, &shader_ci, nullptr, &compute.shader_module)); // Descriptor set layout: binding 0=sampler, 1=Y storage, 2=UV storage, 3=cursor sampler diff --git a/src/platform/linux/shaders/rgb2yuv.comp b/src_assets/linux/assets/shaders/vulkan/rgb2yuv.comp similarity index 100% rename from src/platform/linux/shaders/rgb2yuv.comp rename to src_assets/linux/assets/shaders/vulkan/rgb2yuv.comp From fd36a5044e6144065ac1007f794006a55690b3e9 Mon Sep 17 00:00:00 2001 From: neatnoise Date: Thu, 26 Mar 2026 16:23:55 +0100 Subject: [PATCH 24/29] fix: use Vulkan headers from build-deps, improve portability - Use Vulkan headers from build-deps submodule instead of system SDK - Link against system libvulkan.so (loader is version-agnostic) - Guard sys/sysmacros.h for FreeBSD compatibility - Remove redundant glslang-tools from ci-linux.yml - Set RADV_PERFTEST=video_encode for AMD Vulkan video extensions - Add (default) indicators to Vulkan tuning/rc UI labels - Remove leading underscores from cmake variables (cmake-lint) --- .github/workflows/ci-linux.yml | 1 - cmake/compile_definitions/linux.cmake | 19 ++++++-- cmake/scripts/binary_to_c.cmake | 46 +++++++++---------- packaging/linux/copr/Sunshine.spec | 1 - packaging/sunshine.rb | 1 - scripts/linux_build.sh | 2 - src/platform/linux/misc.cpp | 3 ++ src/platform/linux/vulkan_encode.cpp | 6 ++- .../assets/web/public/assets/locale/en.json | 4 +- 9 files changed, 47 insertions(+), 36 deletions(-) diff --git a/.github/workflows/ci-linux.yml b/.github/workflows/ci-linux.yml index 52601f60ca0..19d4c239ef9 100644 --- a/.github/workflows/ci-linux.yml +++ b/.github/workflows/ci-linux.yml @@ -50,7 +50,6 @@ jobs: sudo add-apt-repository universe sudo apt-get install -y \ - glslang-tools \ libdrm-dev \ libfuse2 \ libgl-dev \ diff --git a/cmake/compile_definitions/linux.cmake b/cmake/compile_definitions/linux.cmake index b3d0baf90fa..56952b62dbc 100644 --- a/cmake/compile_definitions/linux.cmake +++ b/cmake/compile_definitions/linux.cmake @@ -122,7 +122,17 @@ endif() # vulkan video encoding (via FFmpeg) if(${SUNSHINE_ENABLE_VULKAN}) - find_package(Vulkan REQUIRED) + # use Vulkan headers from build-deps submodule (system headers may be too old, e.g. Ubuntu 22.04) + set(VULKAN_HEADERS_DIR "${CMAKE_SOURCE_DIR}/third-party/build-deps/third-party/FFmpeg/Vulkan-Headers/include") + if(NOT EXISTS "${VULKAN_HEADERS_DIR}/vulkan/vulkan.h") + message(FATAL_ERROR "Vulkan headers not found in build-deps submodule") + endif() + + find_library(VULKAN_LIBRARY NAMES vulkan vulkan-1) + if(NOT VULKAN_LIBRARY) + message(FATAL_ERROR "libvulkan not found") + endif() + # prefer glslc, fall back to glslangValidator find_package(Vulkan QUIET COMPONENTS glslc) if(NOT TARGET Vulkan::glslc) @@ -131,11 +141,10 @@ if(${SUNSHINE_ENABLE_VULKAN}) if(NOT TARGET Vulkan::glslc AND NOT TARGET Vulkan::glslangValidator) message(FATAL_ERROR "Vulkan shader compiler not found (need glslc or glslangValidator)") endif() -endif() -if(SUNSHINE_ENABLE_VULKAN AND Vulkan_FOUND) + list(APPEND SUNSHINE_DEFINITIONS SUNSHINE_BUILD_VULKAN=1) - include_directories(SYSTEM ${Vulkan_INCLUDE_DIRS}) - list(APPEND PLATFORM_LIBRARIES ${Vulkan_LIBRARIES}) + include_directories(SYSTEM ${VULKAN_HEADERS_DIR}) + list(APPEND PLATFORM_LIBRARIES ${VULKAN_LIBRARY}) list(APPEND PLATFORM_TARGET_FILES "${CMAKE_SOURCE_DIR}/src/platform/linux/vulkan_encode.h" "${CMAKE_SOURCE_DIR}/src/platform/linux/vulkan_encode.cpp") diff --git a/cmake/scripts/binary_to_c.cmake b/cmake/scripts/binary_to_c.cmake index e63f1dacdbc..d32d0108092 100644 --- a/cmake/scripts/binary_to_c.cmake +++ b/cmake/scripts/binary_to_c.cmake @@ -2,32 +2,32 @@ # Input: SPV_FILE - path to SPIR-V binary # Output: OUT_FILE - path to write C initializer (e.g. {0x07230203, ...}) -file(READ "${SPV_FILE}" _data HEX) -string(LENGTH "${_data}" _hex_len) -math(EXPR _num_bytes "${_hex_len} / 2") -math(EXPR _num_words "${_num_bytes} / 4") -math(EXPR _last "${_num_words} - 1") +file(READ "${SPV_FILE}" data HEX) +string(LENGTH "${data}" hex_len) +math(EXPR num_bytes "${hex_len} / 2") +math(EXPR num_words "${num_bytes} / 4") +math(EXPR last "${num_words} - 1") -set(_out "{") -foreach(_idx RANGE 0 ${_last}) - math(EXPR _off "${_idx} * 8") - math(EXPR _off1 "${_off} + 2") - math(EXPR _off2 "${_off} + 4") - math(EXPR _off3 "${_off} + 6") - string(SUBSTRING "${_data}" ${_off} 2 _b0) - string(SUBSTRING "${_data}" ${_off1} 2 _b1) - string(SUBSTRING "${_data}" ${_off2} 2 _b2) - string(SUBSTRING "${_data}" ${_off3} 2 _b3) +set(out "{") +foreach(idx RANGE 0 ${last}) + math(EXPR off "${idx} * 8") + math(EXPR off1 "${off} + 2") + math(EXPR off2 "${off} + 4") + math(EXPR off3 "${off} + 6") + string(SUBSTRING "${data}" ${off} 2 b0) + string(SUBSTRING "${data}" ${off1} 2 b1) + string(SUBSTRING "${data}" ${off2} 2 b2) + string(SUBSTRING "${data}" ${off3} 2 b3) # little-endian to uint32_t - string(APPEND _out "0x${_b3}${_b2}${_b1}${_b0}") - if(NOT _idx EQUAL _last) - string(APPEND _out ",") + string(APPEND out "0x${b3}${b2}${b1}${b0}") + if(NOT idx EQUAL last) + string(APPEND out ",") endif() - math(EXPR _col "(${_idx} + 1) % 8") - if(_col EQUAL 0) - string(APPEND _out "\n") + math(EXPR col "(${idx} + 1) % 8") + if(col EQUAL 0) + string(APPEND out "\n") endif() endforeach() -string(APPEND _out "}\n") +string(APPEND out "}\n") -file(WRITE "${OUT_FILE}" "${_out}") +file(WRITE "${OUT_FILE}" "${out}") diff --git a/packaging/linux/copr/Sunshine.spec b/packaging/linux/copr/Sunshine.spec index 54f9d66a79b..c3c88baa6e7 100644 --- a/packaging/linux/copr/Sunshine.spec +++ b/packaging/linux/copr/Sunshine.spec @@ -45,7 +45,6 @@ BuildRequires: glslc BuildRequires: pipewire-devel BuildRequires: rpm-build BuildRequires: systemd-rpm-macros -BuildRequires: vulkan-headers BuildRequires: vulkan-loader-devel BuildRequires: wget BuildRequires: which diff --git a/packaging/sunshine.rb b/packaging/sunshine.rb index db133057c84..456634a69b7 100644 --- a/packaging/sunshine.rb +++ b/packaging/sunshine.rb @@ -97,7 +97,6 @@ class Sunshine < Formula depends_on "pipewire" depends_on "pulseaudio" depends_on "systemd" - depends_on "vulkan-headers" depends_on "vulkan-loader" depends_on "wayland" diff --git a/scripts/linux_build.sh b/scripts/linux_build.sh index 41670fdf48f..b0c7eef2943 100755 --- a/scripts/linux_build.sh +++ b/scripts/linux_build.sh @@ -196,7 +196,6 @@ function add_arch_deps() { 'python-setuptools' # glad OpenGL/EGL loader generated, v2.0.0 'shaderc' 'udev' - 'vulkan-headers' 'vulkan-icd-loader' 'wayland' ) @@ -337,7 +336,6 @@ function add_fedora_deps() { "python3-jinja2" # glad OpenGL/EGL loader generator "python3-setuptools" # glad OpenGL/EGL loader generated, v2.0.0 "rpm-build" # if you want to build an RPM binary package - "vulkan-headers" "vulkan-loader-devel" "glslc" "wget" # necessary for cuda install with `run` file diff --git a/src/platform/linux/misc.cpp b/src/platform/linux/misc.cpp index b8421f60d55..7900609f63c 100644 --- a/src/platform/linux/misc.cpp +++ b/src/platform/linux/misc.cpp @@ -1087,6 +1087,9 @@ namespace platf { // https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/30039 set_env("AMD_DEBUG", "lowlatencyenc"); + // enable Vulkan video extensions for AMD RADV + set_env("RADV_PERFTEST", "video_encode"); + // These are allowed to fail. gbm::init(); diff --git a/src/platform/linux/vulkan_encode.cpp b/src/platform/linux/vulkan_encode.cpp index 25d532056a0..bf72e7afe8f 100644 --- a/src/platform/linux/vulkan_encode.cpp +++ b/src/platform/linux/vulkan_encode.cpp @@ -7,7 +7,11 @@ #include #include #include -#include +#if defined(__FreeBSD__) + #include +#else + #include +#endif #include extern "C" { diff --git a/src_assets/common/assets/web/public/assets/locale/en.json b/src_assets/common/assets/web/public/assets/locale/en.json index d3a878e0c79..8121e84ceaa 100644 --- a/src_assets/common/assets/web/public/assets/locale/en.json +++ b/src_assets/common/assets/web/public/assets/locale/en.json @@ -381,13 +381,13 @@ "vk_tune": "Tuning", "vk_tune_desc": "Low latency modes reduce encoding delay at the cost of quality.", "vk_tune_hq": "High Quality (hq)", - "vk_tune_ll": "Low Latency (ll)", + "vk_tune_ll": "Low Latency (ll) (default)", "vk_tune_ull": "Ultra Low Latency (ull)", "vk_rc_cbr": "CBR (Constant Bitrate)", "vk_rc_cqp": "CQP (Constant QP)", "vk_rc_mode": "Rate Control", "vk_rc_mode_desc": "Rate control mode for encoding. Auto lets the driver decide.", - "vk_rc_vbr": "VBR (Variable Bitrate)", + "vk_rc_vbr": "VBR (Variable Bitrate) (default)", "virtual_sink": "Virtual Sink", "virtual_sink_desc": "Manually specify a virtual audio device to use. If unset, the device is chosen automatically. We strongly recommend leaving this field blank to use automatic device selection!", "virtual_sink_placeholder": "Steam Streaming Speakers", From 0872a099d0f17cde8b192d4bcfb394e89b4131f1 Mon Sep 17 00:00:00 2001 From: neatnoise Date: Sun, 29 Mar 2026 18:15:55 +0200 Subject: [PATCH 25/29] style: move vulkan.h include to top of file --- src/platform/linux/vulkan_encode.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/platform/linux/vulkan_encode.cpp b/src/platform/linux/vulkan_encode.cpp index bf72e7afe8f..3113e11fd48 100644 --- a/src/platform/linux/vulkan_encode.cpp +++ b/src/platform/linux/vulkan_encode.cpp @@ -13,6 +13,7 @@ #include #endif #include +#include extern "C" { #include @@ -32,8 +33,6 @@ static const std::vector rgb2yuv_comp_spv_data ; static const size_t rgb2yuv_comp_spv_size = rgb2yuv_comp_spv_data.size() * sizeof(uint32_t); -#include - using namespace std::literals; namespace vk { From e3cd494ee97b153dbbfa2b1bee1c538facb6fc3a Mon Sep 17 00:00:00 2001 From: neatnoise Date: Sun, 29 Mar 2026 22:52:11 +0200 Subject: [PATCH 26/29] fix: use find_program for shader compiler, fix packaging deps - Replace find_package(Vulkan COMPONENTS glslc) with find_program() so shader compiler detection works without system Vulkan headers - Move glslc BuildRequires to Fedora-only, add shaderc for OpenSUSE - Add shaderc dependency to Homebrew formula --- cmake/compile_definitions/linux.cmake | 14 +++++++------- packaging/linux/copr/Sunshine.spec | 3 ++- packaging/sunshine.rb | 1 + 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/cmake/compile_definitions/linux.cmake b/cmake/compile_definitions/linux.cmake index 56952b62dbc..c40c5460b3b 100644 --- a/cmake/compile_definitions/linux.cmake +++ b/cmake/compile_definitions/linux.cmake @@ -134,11 +134,11 @@ if(${SUNSHINE_ENABLE_VULKAN}) endif() # prefer glslc, fall back to glslangValidator - find_package(Vulkan QUIET COMPONENTS glslc) - if(NOT TARGET Vulkan::glslc) - find_package(Vulkan QUIET COMPONENTS glslangValidator) + find_program(GLSLC_EXECUTABLE glslc) + if(NOT GLSLC_EXECUTABLE) + find_program(GLSLANG_EXECUTABLE glslangValidator) endif() - if(NOT TARGET Vulkan::glslc AND NOT TARGET Vulkan::glslangValidator) + if(NOT GLSLC_EXECUTABLE AND NOT GLSLANG_EXECUTABLE) message(FATAL_ERROR "Vulkan shader compiler not found (need glslc or glslangValidator)") endif() @@ -157,17 +157,17 @@ if(${SUNSHINE_ENABLE_VULKAN}) file(MAKE_DIRECTORY "${VULKAN_SHADER_DIR}") - if(TARGET Vulkan::glslc) + if(GLSLC_EXECUTABLE) add_custom_command( OUTPUT "${VULKAN_SHADER_SPV}" - COMMAND Vulkan::glslc -O "${VULKAN_SHADER_SOURCE}" -o "${VULKAN_SHADER_SPV}" + COMMAND ${GLSLC_EXECUTABLE} -O "${VULKAN_SHADER_SOURCE}" -o "${VULKAN_SHADER_SPV}" DEPENDS "${VULKAN_SHADER_SOURCE}" COMMENT "Compiling Vulkan shader rgb2yuv.comp (glslc)" VERBATIM) else() add_custom_command( OUTPUT "${VULKAN_SHADER_SPV}" - COMMAND Vulkan::glslangValidator -V -o "${VULKAN_SHADER_SPV}" "${VULKAN_SHADER_SOURCE}" + COMMAND ${GLSLANG_EXECUTABLE} -V -o "${VULKAN_SHADER_SPV}" "${VULKAN_SHADER_SOURCE}" DEPENDS "${VULKAN_SHADER_SOURCE}" COMMENT "Compiling Vulkan shader rgb2yuv.comp (glslangValidator)" VERBATIM) diff --git a/packaging/linux/copr/Sunshine.spec b/packaging/linux/copr/Sunshine.spec index c3c88baa6e7..5a0e5366602 100644 --- a/packaging/linux/copr/Sunshine.spec +++ b/packaging/linux/copr/Sunshine.spec @@ -41,7 +41,6 @@ BuildRequires: libXinerama-devel BuildRequires: libXrandr-devel BuildRequires: libXtst-devel BuildRequires: openssl-devel -BuildRequires: glslc BuildRequires: pipewire-devel BuildRequires: rpm-build BuildRequires: systemd-rpm-macros @@ -53,6 +52,7 @@ BuildRequires: which # Fedora-specific BuildRequires BuildRequires: appstream # BuildRequires: boost-devel >= 1.86.0 +BuildRequires: glslc BuildRequires: libappstream-glib %if 0%{fedora} > 43 # needed for npm from nvm @@ -93,6 +93,7 @@ BuildRequires: npm BuildRequires: python311 BuildRequires: python311-Jinja2 BuildRequires: python311-setuptools +BuildRequires: shaderc BuildRequires: udev # for unit tests BuildRequires: xvfb-run diff --git a/packaging/sunshine.rb b/packaging/sunshine.rb index 456634a69b7..fdde9350d1b 100644 --- a/packaging/sunshine.rb +++ b/packaging/sunshine.rb @@ -96,6 +96,7 @@ class Sunshine < Formula depends_on "pango" depends_on "pipewire" depends_on "pulseaudio" + depends_on "shaderc" depends_on "systemd" depends_on "vulkan-loader" depends_on "wayland" From dac503b0baf2a99a40d70c7a866e9783f7de1343 Mon Sep 17 00:00:00 2001 From: neatnoise Date: Mon, 30 Mar 2026 16:07:00 +0200 Subject: [PATCH 27/29] fix: cmake-lint errors, clang-format, and alphabetical locale keys --- cmake/scripts/binary_to_c.cmake | 14 ++++++------- src/platform/linux/kmsgrab.cpp | 5 +---- src/platform/linux/misc.cpp | 3 +-- src/platform/linux/portalgrab.cpp | 6 ++---- src/video.cpp | 21 +++++++------------ .../assets/web/public/assets/locale/en.json | 10 ++++----- 6 files changed, 24 insertions(+), 35 deletions(-) diff --git a/cmake/scripts/binary_to_c.cmake b/cmake/scripts/binary_to_c.cmake index d32d0108092..b3ea7a54e9f 100644 --- a/cmake/scripts/binary_to_c.cmake +++ b/cmake/scripts/binary_to_c.cmake @@ -8,8 +8,8 @@ math(EXPR num_bytes "${hex_len} / 2") math(EXPR num_words "${num_bytes} / 4") math(EXPR last "${num_words} - 1") -set(out "{") -foreach(idx RANGE 0 ${last}) +set(_out "{") +foreach(idx RANGE ${last}) math(EXPR off "${idx} * 8") math(EXPR off1 "${off} + 2") math(EXPR off2 "${off} + 4") @@ -19,15 +19,15 @@ foreach(idx RANGE 0 ${last}) string(SUBSTRING "${data}" ${off2} 2 b2) string(SUBSTRING "${data}" ${off3} 2 b3) # little-endian to uint32_t - string(APPEND out "0x${b3}${b2}${b1}${b0}") + string(APPEND _out "0x${b3}${b2}${b1}${b0}") if(NOT idx EQUAL last) - string(APPEND out ",") + string(APPEND _out ",") endif() math(EXPR col "(${idx} + 1) % 8") if(col EQUAL 0) - string(APPEND out "\n") + string(APPEND _out "\n") endif() endforeach() -string(APPEND out "}\n") +string(APPEND _out "}\n") -file(WRITE "${OUT_FILE}" "${out}") +file(WRITE "${OUT_FILE}" "${_out}") diff --git a/src/platform/linux/kmsgrab.cpp b/src/platform/linux/kmsgrab.cpp index 3bd641f2851..11571c7c361 100644 --- a/src/platform/linux/kmsgrab.cpp +++ b/src/platform/linux/kmsgrab.cpp @@ -961,10 +961,7 @@ namespace platf { } else if (plane->fb_id != captured_cursor.fb_id) { BOOST_LOG(debug) << "Refreshing cursor image after FB changed"sv; cursor_dirty = true; - } else if (*prop_src_x != captured_cursor.prop_src_x || - *prop_src_y != captured_cursor.prop_src_y || - *prop_src_w != captured_cursor.prop_src_w || - *prop_src_h != captured_cursor.prop_src_h) { + } else if (*prop_src_x != captured_cursor.prop_src_x || *prop_src_y != captured_cursor.prop_src_y || *prop_src_w != captured_cursor.prop_src_w || *prop_src_h != captured_cursor.prop_src_h) { BOOST_LOG(debug) << "Refreshing cursor image after source dimensions changed"sv; cursor_dirty = true; } diff --git a/src/platform/linux/misc.cpp b/src/platform/linux/misc.cpp index 7900609f63c..ba40a802873 100644 --- a/src/platform/linux/misc.cpp +++ b/src/platform/linux/misc.cpp @@ -250,8 +250,7 @@ namespace platf { if (!interface_name.empty()) { // Find the AF_LINK entry for this interface to get MAC address for (auto pos = ifaddrs.get(); pos != nullptr; pos = pos->ifa_next) { - if (pos->ifa_addr && pos->ifa_addr->sa_family == AF_LINK && - interface_name == pos->ifa_name) { + if (pos->ifa_addr && pos->ifa_addr->sa_family == AF_LINK && interface_name == pos->ifa_name) { auto sdl = (struct sockaddr_dl *) pos->ifa_addr; auto mac = (unsigned char *) LLADDR(sdl); diff --git a/src/platform/linux/portalgrab.cpp b/src/platform/linux/portalgrab.cpp index fa5da4367de..badb4be2936 100644 --- a/src/platform/linux/portalgrab.cpp +++ b/src/platform/linux/portalgrab.cpp @@ -1271,8 +1271,7 @@ namespace portal { } // Check previous logical dimensions - if (previous_width.load() == width && - previous_height.load() == height) { + if (previous_width.load() == width && previous_height.load() == height) { if (capture_running.load()) { { std::scoped_lock lock(pipewire.frame_mutex()); @@ -1285,8 +1284,7 @@ namespace portal { previous_height.store(height); } - if (negotiated_w > 0 && negotiated_h > 0 && - (negotiated_w != width || negotiated_h != height)) { + if (negotiated_w > 0 && negotiated_h > 0 && (negotiated_w != width || negotiated_h != height)) { BOOST_LOG(info) << "Using negotiated resolution "sv << negotiated_w << "x" << negotiated_h; diff --git a/src/video.cpp b/src/video.cpp index 2f30c4ab510..67234bc112d 100644 --- a/src/video.cpp +++ b/src/video.cpp @@ -1015,7 +1015,7 @@ namespace video { LIMITED_GOP_SIZE | PARALLEL_ENCODING | NO_RC_BUF_LIMIT }; -#ifdef SUNSHINE_BUILD_VULKAN + #ifdef SUNSHINE_BUILD_VULKAN encoder_t vulkan { "vulkan"sv, std::make_unique( @@ -1084,7 +1084,7 @@ namespace video { }, LIMITED_GOP_SIZE | PARALLEL_ENCODING }; -#endif // SUNSHINE_BUILD_VULKAN + #endif // SUNSHINE_BUILD_VULKAN #endif // linux #ifdef __APPLE__ @@ -1165,9 +1165,9 @@ namespace video { &mediafoundation, #endif #if defined(__linux__) || defined(linux) || defined(__linux) || defined(__FreeBSD__) -#ifdef SUNSHINE_BUILD_VULKAN + #ifdef SUNSHINE_BUILD_VULKAN &vulkan, -#endif + #endif &vaapi, #endif #ifdef __APPLE__ @@ -2753,9 +2753,7 @@ namespace video { // Test 4:4:4 HDR first. If 4:4:4 is supported, 4:2:0 should also be supported. config.chromaSamplingType = 1; - if ((encoder.flags & YUV444_SUPPORT) && - disp->is_codec_supported(encoder_codec_name, config) && - validate_config(disp, encoder, config) >= 0) { + if ((encoder.flags & YUV444_SUPPORT) && disp->is_codec_supported(encoder_codec_name, config) && validate_config(disp, encoder, config) >= 0) { flag_map[encoder_t::DYNAMIC_RANGE] = true; flag_map[encoder_t::YUV444] = true; return; @@ -2765,8 +2763,7 @@ namespace video { // Test 4:2:0 HDR config.chromaSamplingType = 0; - if (disp->is_codec_supported(encoder_codec_name, config) && - validate_config(disp, encoder, config) >= 0) { + if (disp->is_codec_supported(encoder_codec_name, config) && validate_config(disp, encoder, config) >= 0) { flag_map[encoder_t::DYNAMIC_RANGE] = true; } else { flag_map[encoder_t::DYNAMIC_RANGE] = false; @@ -2874,15 +2871,13 @@ namespace video { } // Skip it if it doesn't support the specified codec at all - if ((active_hevc_mode >= 2 && !encoder->hevc[encoder_t::PASSED]) || - (active_av1_mode >= 2 && !encoder->av1[encoder_t::PASSED])) { + if ((active_hevc_mode >= 2 && !encoder->hevc[encoder_t::PASSED]) || (active_av1_mode >= 2 && !encoder->av1[encoder_t::PASSED])) { pos++; continue; } // Skip it if it doesn't support HDR on the specified codec - if ((active_hevc_mode == 3 && !encoder->hevc[encoder_t::DYNAMIC_RANGE]) || - (active_av1_mode == 3 && !encoder->av1[encoder_t::DYNAMIC_RANGE])) { + if ((active_hevc_mode == 3 && !encoder->hevc[encoder_t::DYNAMIC_RANGE]) || (active_av1_mode == 3 && !encoder->av1[encoder_t::DYNAMIC_RANGE])) { pos++; continue; } diff --git a/src_assets/common/assets/web/public/assets/locale/en.json b/src_assets/common/assets/web/public/assets/locale/en.json index 8121e84ceaa..53463b78d1e 100644 --- a/src_assets/common/assets/web/public/assets/locale/en.json +++ b/src_assets/common/assets/web/public/assets/locale/en.json @@ -378,16 +378,16 @@ "upnp_desc": "Automatically configure port forwarding for streaming over the Internet", "vaapi_strict_rc_buffer": "Strictly enforce frame bitrate limits for H.264/HEVC on AMD GPUs", "vaapi_strict_rc_buffer_desc": "Enabling this option can avoid dropped frames over the network during scene changes, but video quality may be reduced during motion.", - "vk_tune": "Tuning", - "vk_tune_desc": "Low latency modes reduce encoding delay at the cost of quality.", - "vk_tune_hq": "High Quality (hq)", - "vk_tune_ll": "Low Latency (ll) (default)", - "vk_tune_ull": "Ultra Low Latency (ull)", "vk_rc_cbr": "CBR (Constant Bitrate)", "vk_rc_cqp": "CQP (Constant QP)", "vk_rc_mode": "Rate Control", "vk_rc_mode_desc": "Rate control mode for encoding. Auto lets the driver decide.", "vk_rc_vbr": "VBR (Variable Bitrate) (default)", + "vk_tune": "Tuning", + "vk_tune_desc": "Low latency modes reduce encoding delay at the cost of quality.", + "vk_tune_hq": "High Quality (hq)", + "vk_tune_ll": "Low Latency (ll) (default)", + "vk_tune_ull": "Ultra Low Latency (ull)", "virtual_sink": "Virtual Sink", "virtual_sink_desc": "Manually specify a virtual audio device to use. If unset, the device is chosen automatically. We strongly recommend leaving this field blank to use automatic device selection!", "virtual_sink_placeholder": "Steam Streaming Speakers", From 6c55303ca548a4976a8f6e59b4084d1b447e1c65 Mon Sep 17 00:00:00 2001 From: neatnoise Date: Mon, 30 Mar 2026 17:27:18 +0200 Subject: [PATCH 28/29] fix: cmake-lint E1120 and C0307 in binary_to_c.cmake --- cmake/scripts/binary_to_c.cmake | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/cmake/scripts/binary_to_c.cmake b/cmake/scripts/binary_to_c.cmake index b3ea7a54e9f..b1406477e45 100644 --- a/cmake/scripts/binary_to_c.cmake +++ b/cmake/scripts/binary_to_c.cmake @@ -9,8 +9,9 @@ math(EXPR num_words "${num_bytes} / 4") math(EXPR last "${num_words} - 1") set(_out "{") -foreach(idx RANGE ${last}) - math(EXPR off "${idx} * 8") +set(_idx 0) +while(_idx LESS_EQUAL last) + math(EXPR off "${_idx} * 8") math(EXPR off1 "${off} + 2") math(EXPR off2 "${off} + 4") math(EXPR off3 "${off} + 6") @@ -20,14 +21,15 @@ foreach(idx RANGE ${last}) string(SUBSTRING "${data}" ${off3} 2 b3) # little-endian to uint32_t string(APPEND _out "0x${b3}${b2}${b1}${b0}") - if(NOT idx EQUAL last) + if(NOT _idx EQUAL last) string(APPEND _out ",") endif() - math(EXPR col "(${idx} + 1) % 8") - if(col EQUAL 0) + math(EXPR _col "(${_idx} + 1) % 8") + if(_col EQUAL 0) string(APPEND _out "\n") endif() -endforeach() + math(EXPR _idx "${_idx} + 1") +endwhile() string(APPEND _out "}\n") file(WRITE "${OUT_FILE}" "${_out}") From c960341d2f38403cabc2de9d9c91b15c55f140c3 Mon Sep 17 00:00:00 2001 From: neatnoise Date: Tue, 31 Mar 2026 00:23:09 +0200 Subject: [PATCH 29/29] fix: openSUSE packaging - correct vulkan package names, disable vulkan on Leap - Move vulkan-loader-devel from common to Fedora-specific section - Add vulkan-devel for openSUSE Tumbleweed - Use libvulkan1 instead of vulkan-loader for openSUSE runtime dep - Disable Vulkan on openSUSE Leap (shaderc/glslang not in official repos) - Skip vulkan/shaderc BuildRequires on Leap via sle_version conditional --- packaging/linux/copr/Sunshine.spec | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/packaging/linux/copr/Sunshine.spec b/packaging/linux/copr/Sunshine.spec index 5a0e5366602..dd8801e0a2f 100644 --- a/packaging/linux/copr/Sunshine.spec +++ b/packaging/linux/copr/Sunshine.spec @@ -44,7 +44,6 @@ BuildRequires: openssl-devel BuildRequires: pipewire-devel BuildRequires: rpm-build BuildRequires: systemd-rpm-macros -BuildRequires: vulkan-loader-devel BuildRequires: wget BuildRequires: which @@ -54,6 +53,7 @@ BuildRequires: appstream # BuildRequires: boost-devel >= 1.86.0 BuildRequires: glslc BuildRequires: libappstream-glib +BuildRequires: vulkan-loader-devel %if 0%{fedora} > 43 # needed for npm from nvm BuildRequires: libatomic @@ -93,8 +93,13 @@ BuildRequires: npm BuildRequires: python311 BuildRequires: python311-Jinja2 BuildRequires: python311-setuptools +%if !0%{?sle_version} BuildRequires: shaderc +%endif BuildRequires: udev +%if !0%{?sle_version} +BuildRequires: vulkan-devel +%endif # for unit tests BuildRequires: xvfb-run %endif @@ -177,7 +182,9 @@ Requires: libX11-6 Requires: libnuma1 Requires: libopenssl3 Requires: libpulse0 -Requires: vulkan-loader +%if !0%{?sle_version} +Requires: libvulkan1 +%endif %endif %description @@ -328,6 +335,11 @@ export BRANCH=%{branch} export BUILD_VERSION=v%{build_version} export COMMIT=%{commit} +# Disable Vulkan on openSUSE Leap (shaderc/glslang not in official repos) +%if 0%{?sle_version} +cmake_args+=("-DSUNSHINE_ENABLE_VULKAN=OFF") +%endif + # cmake cd %{_builddir}/Sunshine echo "cmake args:"