diff --git a/glfw/source-info.json b/glfw/source-info.json index cef1ba66f..165c95335 100644 --- a/glfw/source-info.json +++ b/glfw/source-info.json @@ -81,6 +81,7 @@ "unstable/tablet/tablet-unstable-v2.xml", "staging/cursor-shape/cursor-shape-v1.xml", "staging/fractional-scale/fractional-scale-v1.xml", + "staging/single-pixel-buffer/single-pixel-buffer-v1.xml", "kwin-blur-v1.xml", "wlr-layer-shell-unstable-v1.xml" diff --git a/glfw/wl_init.c b/glfw/wl_init.c index ade814823..e9992553c 100644 --- a/glfw/wl_init.c +++ b/glfw/wl_init.c @@ -724,6 +724,9 @@ static void registryHandleGlobal(void* data UNUSED, _glfwSetupWaylandPrimarySelectionDevice(); } } + else if (is(wp_single_pixel_buffer_manager_v1)) { + _glfw.wl.wp_single_pixel_buffer_manager_v1 = wl_registry_bind(registry, name, &wp_single_pixel_buffer_manager_v1_interface, 1); + } else if (is(xdg_activation_v1)) { _glfw.wl.xdg_activation_v1 = wl_registry_bind(registry, name, &xdg_activation_v1_interface, 1); } @@ -992,6 +995,8 @@ void _glfwPlatformTerminate(void) zwp_primary_selection_device_manager_v1_destroy(_glfw.wl.primarySelectionDeviceManager); if (_glfw.wl.xdg_activation_v1) xdg_activation_v1_destroy(_glfw.wl.xdg_activation_v1); + if (_glfw.wl.wp_single_pixel_buffer_manager_v1) + wp_single_pixel_buffer_manager_v1_destroy(_glfw.wl.wp_single_pixel_buffer_manager_v1); if (_glfw.wl.wp_cursor_shape_manager_v1) wp_cursor_shape_manager_v1_destroy(_glfw.wl.wp_cursor_shape_manager_v1); if (_glfw.wl.wp_viewporter) diff --git a/glfw/wl_platform.h b/glfw/wl_platform.h index 0c9c6075b..6834243ee 100644 --- a/glfw/wl_platform.h +++ b/glfw/wl_platform.h @@ -64,6 +64,7 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR #include "wayland-viewporter-client-protocol.h" #include "wayland-kwin-blur-v1-client-protocol.h" #include "wayland-wlr-layer-shell-unstable-v1-client-protocol.h" +#include "wayland-single-pixel-buffer-v1-client-protocol.h" #define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) #define _glfw_dlclose(handle) dlclose(handle) @@ -308,6 +309,7 @@ typedef struct _GLFWlibraryWayland struct wp_viewporter *wp_viewporter; struct org_kde_kwin_blur_manager *org_kde_kwin_blur_manager; struct zwlr_layer_shell_v1* zwlr_layer_shell_v1; uint32_t zwlr_layer_shell_v1_version; + struct wp_single_pixel_buffer_manager_v1 *wp_single_pixel_buffer_manager_v1; int compositorVersion; int seatVersion; diff --git a/glfw/wl_window.c b/glfw/wl_window.c index 405c90762..9ed5dcce4 100644 --- a/glfw/wl_window.c +++ b/glfw/wl_window.c @@ -752,28 +752,23 @@ apply_xdg_configure_changes(_GLFWwindow *window) { commit_window_surface_if_safe(window); window->wl.pending_state = 0; } +typedef union pixel { + struct { + uint8_t blue, green, red, alpha; + }; + uint32_t value; +} pixel; -static bool -attach_temp_buffer_during_window_creation(_GLFWwindow *window) { - int width, height; - _glfwPlatformGetFramebufferSize(window, &width, &height); +static struct wl_buffer* +create_single_color_buffer(int width, int height, pixel color) { + int shm_format = color.alpha == 0xff ? WL_SHM_FORMAT_XRGB8888 : WL_SHM_FORMAT_ARGB8888; const size_t size = 4 * width * height; int fd = createAnonymousFile(size); if (fd < 0) { _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: failed to create anonymous file"); - return false; + return NULL; } uint32_t *shm_data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - union { - struct { - uint8_t blue, green, red, alpha; - }; - uint32_t value; - } color; - color.value = _glfw.hints.window.wl.bgcolor; - int shm_format = WL_SHM_FORMAT_ARGB8888; - if (!window->wl.transparent) { color.alpha = 0xff; shm_format = WL_SHM_FORMAT_XRGB8888; } - else if (color.alpha == 0) color.value = 0; // fully transparent blends best with black and we can use memset // convert to pre-multiplied alpha float alpha = color.alpha / 255.f; color.red = (uint8_t)(alpha * color.red); color.green = (uint8_t)(alpha * color.green); color.blue = (uint8_t)(alpha * color.blue); if (color.value) for (size_t i = 0; i < size/4; i++) shm_data[i] = color.value; @@ -781,25 +776,56 @@ attach_temp_buffer_during_window_creation(_GLFWwindow *window) { if (!shm_data) { close(fd); _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: failed to mmap anonymous file"); - return false; + return NULL; } struct wl_shm_pool *pool = wl_shm_create_pool(_glfw.wl.shm, fd, size); if (!pool) { close(fd); munmap(shm_data, size); _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: failed to create wl_shm_pool of size: %zu", size); - return false; + return NULL; } struct wl_buffer *buffer = wl_shm_pool_create_buffer(pool, 0, width, height, width * 4, shm_format); wl_shm_pool_destroy(pool); munmap(shm_data, size); close(fd); if (!buffer) { _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: failed to create wl_buffer of size: %zu", size); - return false; + return NULL; } - if (window->wl.temp_buffer_used_during_window_creation) wl_buffer_destroy(window->wl.temp_buffer_used_during_window_creation); - window->wl.temp_buffer_used_during_window_creation = buffer; - wl_surface_set_buffer_scale(window->wl.surface, window->wl.fractional_scale ? 1: _glfwWaylandIntegerWindowScale(window)); - wl_surface_attach(window->wl.surface, buffer, 0, 0); - if (window->wl.wp_viewport) wp_viewport_set_destination(window->wl.wp_viewport, window->wl.width, window->wl.height); + return buffer; +} + +static bool +attach_temp_buffer_during_window_creation(_GLFWwindow *window) { + pixel color; + color.value = _glfw.hints.window.wl.bgcolor; + if (!window->wl.transparent) color.alpha = 0xff; + else if (color.alpha == 0) color.value = 0; // fully transparent blends best with black and we can use memset + + if (window->wl.temp_buffer_used_during_window_creation) { + wl_buffer_destroy(window->wl.temp_buffer_used_during_window_creation); + window->wl.temp_buffer_used_during_window_creation = NULL; + } + int width, height; + _glfwPlatformGetFramebufferSize(window, &width, &height); + + if (window->wl.wp_viewport) { + if (_glfw.wl.wp_single_pixel_buffer_manager_v1) { + window->wl.temp_buffer_used_during_window_creation = wp_single_pixel_buffer_manager_v1_create_u32_rgba_buffer(_glfw.wl.wp_single_pixel_buffer_manager_v1, color.red, color.green, color.blue, color.alpha); + if (!window->wl.temp_buffer_used_during_window_creation) { + _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: failed to create single pixel buffer"); + return false; + } + } else { + window->wl.temp_buffer_used_during_window_creation = create_single_color_buffer(1, 1, color); + if (!window->wl.temp_buffer_used_during_window_creation) return false; + } + wl_surface_set_buffer_scale(window->wl.surface, 1); + wp_viewport_set_destination(window->wl.wp_viewport, window->wl.width, window->wl.height); + } else { + window->wl.temp_buffer_used_during_window_creation = create_single_color_buffer(1, 1, color); + if (!window->wl.temp_buffer_used_during_window_creation) return false; + wl_surface_set_buffer_scale(window->wl.surface, window->wl.fractional_scale ? 1: _glfwWaylandIntegerWindowScale(window)); + } + wl_surface_attach(window->wl.surface, window->wl.temp_buffer_used_during_window_creation, 0, 0); wl_surface_commit(window->wl.surface); debug("Attached temp buffer during window creation of size: %dx%d\n", width, height); return true;