|
26 | 26 | #include <cerrno> |
27 | 27 | #include <chrono> |
28 | 28 | #include <algorithm> |
| 29 | +#include <cmath> |
29 | 30 |
|
30 | 31 | #include <vulkan/vulkan.h> |
31 | 32 | #include <vulkan/vulkan_wayland.h> |
|
37 | 38 | #include <wayland-client.h> |
38 | 39 | #include "xdg-shell-client-protocol.h" |
39 | 40 | #include "xdg-decoration-client-protocol.h" |
| 41 | +#include "viewporter-client-protocol.h" |
40 | 42 | #include <xkbcommon/xkbcommon.h> |
41 | 43 | #include <linux/input-event-codes.h> |
42 | 44 |
|
@@ -353,6 +355,10 @@ int32_t GPUDisplayFrontendWayland::FrontendMain() |
353 | 355 | wl_seat_add_listener(me->mSeat, &me->mSeatListener, me); |
354 | 356 | } else if (strcmp(interface, zxdg_decoration_manager_v1_interface.name) == 0) { |
355 | 357 | me->mDecManager = (zxdg_decoration_manager_v1*)wl_registry_bind(registry, name, &zxdg_decoration_manager_v1_interface, 1); |
| 358 | + } else if (strcmp(interface, wp_viewporter_interface.name) == 0) { |
| 359 | + me->mViewporter = (wp_viewporter*)wl_registry_bind(registry, name, &wp_viewporter_interface, 1); |
| 360 | + } else if (strcmp(interface, wp_fractional_scale_manager_v1_interface.name) == 0) { |
| 361 | + me->mFractionalScaleManager = (wp_fractional_scale_manager_v1*)wl_registry_bind(registry, name, &wp_fractional_scale_manager_v1_interface, 1); |
356 | 362 | } |
357 | 363 | }; |
358 | 364 | auto registry_global_remove = [](void* data, wl_registry* registry, uint32_t name) { |
@@ -416,6 +422,18 @@ int32_t GPUDisplayFrontendWayland::FrontendMain() |
416 | 422 | }; |
417 | 423 | wl_surface_add_listener(mSurface, &mSurfaceListener, this); |
418 | 424 |
|
| 425 | + if (mViewporter && mFractionalScaleManager) { |
| 426 | + auto fractional_scale_preferred_scale = [](void* data, wp_fractional_scale_v1* fractional_scale, uint32_t scale) { |
| 427 | + GPUDisplayFrontendWayland* me = (GPUDisplayFrontendWayland*)data; |
| 428 | + me->mFractionalScale120 = scale; |
| 429 | + me->updateScale(); |
| 430 | + }; |
| 431 | + mFractionalScaleListener = wp_fractional_scale_v1_listener{.preferred_scale = fractional_scale_preferred_scale}; |
| 432 | + mViewport = wp_viewporter_get_viewport(mViewporter, mSurface); |
| 433 | + mFractionalScale = wp_fractional_scale_manager_v1_get_fractional_scale(mFractionalScaleManager, mSurface); |
| 434 | + wp_fractional_scale_v1_add_listener(mFractionalScale, &mFractionalScaleListener, this); |
| 435 | + } |
| 436 | + |
419 | 437 | mXdgSurface = xdg_wm_base_get_xdg_surface(mXdgBase, mSurface); |
420 | 438 | if (mXdgSurface == nullptr) { |
421 | 439 | throw std::runtime_error("Error creating wayland xdg surface"); |
@@ -594,9 +612,25 @@ int32_t GPUDisplayFrontendWayland::FrontendMain() |
594 | 612 | zxdg_toplevel_decoration_v1_destroy(mXdgDecoration); |
595 | 613 | mXdgDecoration = nullptr; |
596 | 614 | } |
| 615 | + if (mFractionalScale) { |
| 616 | + wp_fractional_scale_v1_destroy(mFractionalScale); |
| 617 | + mFractionalScale = nullptr; |
| 618 | + } |
| 619 | + if (mViewport) { |
| 620 | + wp_viewport_destroy(mViewport); |
| 621 | + mViewport = nullptr; |
| 622 | + } |
597 | 623 | xdg_toplevel_destroy(mXdgToplevel); |
598 | 624 | xdg_surface_destroy(mXdgSurface); |
599 | 625 | wl_surface_destroy(mSurface); |
| 626 | + if (mFractionalScaleManager) { |
| 627 | + wp_fractional_scale_manager_v1_destroy(mFractionalScaleManager); |
| 628 | + mFractionalScaleManager = nullptr; |
| 629 | + } |
| 630 | + if (mViewporter) { |
| 631 | + wp_viewporter_destroy(mViewporter); |
| 632 | + mViewporter = nullptr; |
| 633 | + } |
600 | 634 | if (mDecManager) { |
601 | 635 | zxdg_decoration_manager_v1_destroy(mDecManager); |
602 | 636 | mDecManager = nullptr; |
@@ -665,25 +699,37 @@ GPUDisplayFrontendWayland::OutputInfo* GPUDisplayFrontendWayland::findOutput(wl_ |
665 | 699 |
|
666 | 700 | void GPUDisplayFrontendWayland::updateScale() |
667 | 701 | { |
668 | | - int32_t scale = mPreferredScale; |
669 | | - if (scale == 0) { |
670 | | - scale = 1; |
671 | | - for (auto* output : mSurfaceOutputs) { |
672 | | - if (auto* o = findOutput(output)) { |
673 | | - scale = std::max(scale, o->scale); |
| 702 | + double scale; |
| 703 | + if (mFractionalScale) { |
| 704 | + scale = mFractionalScale120 ? mFractionalScale120 / 120. : 1.; |
| 705 | + } else { |
| 706 | + int32_t intScale = mPreferredScale; |
| 707 | + if (intScale == 0) { |
| 708 | + intScale = 1; |
| 709 | + for (auto* output : mSurfaceOutputs) { |
| 710 | + if (auto* o = findOutput(output)) { |
| 711 | + intScale = std::max(intScale, o->scale); |
| 712 | + } |
674 | 713 | } |
675 | 714 | } |
| 715 | + scale = intScale; |
676 | 716 | } |
677 | 717 | if (scale != mScale && mSurface) { |
678 | 718 | mScale = scale; |
679 | | - wl_surface_set_buffer_scale(mSurface, mScale); // Applied with the next commit, i.e. the next present, which happens after the swapchain was recreated with the new size by ResizeScene |
| 719 | + if (!mFractionalScale) { |
| 720 | + wl_surface_set_buffer_scale(mSurface, (int32_t)mScale); // Applied with the next commit, i.e. the next present, which happens after the swapchain was recreated with the new size by ResizeScene |
| 721 | + } |
680 | 722 | updateSize(); |
681 | 723 | } |
682 | 724 | } |
683 | 725 |
|
684 | 726 | void GPUDisplayFrontendWayland::updateSize() |
685 | 727 | { |
686 | | - const int32_t width = mWidthLogical * mScale, height = mHeightLogical * mScale; |
| 728 | + if (mViewport) { |
| 729 | + wp_viewport_set_destination(mViewport, mWidthLogical, mHeightLogical); // Surface size in logical coordinates, independent of the buffer size, applied with the next present |
| 730 | + } |
| 731 | + const int32_t width = mFractionalScale ? (int32_t)std::lround(mWidthLogical * mScale) : (mWidthLogical * (int32_t)mScale); |
| 732 | + const int32_t height = mFractionalScale ? (int32_t)std::lround(mHeightLogical * mScale) : (mHeightLogical * (int32_t)mScale); |
687 | 733 | if (width != mDisplayWidth || height != mDisplayHeight) { |
688 | 734 | if (mDisplayRunning) { |
689 | 735 | ResizeScene(width, height); // Swapchain is recreated by the backend, Vulkan WSI commits the new buffer |
|
0 commit comments