diff --git a/src/video/wayland/SDL_waylandcolor.c b/src/video/wayland/SDL_waylandcolor.c index 148a3416c1..dfc69bb5f4 100644 --- a/src/video/wayland/SDL_waylandcolor.c +++ b/src/video/wayland/SDL_waylandcolor.c @@ -27,31 +27,87 @@ #include "SDL_waylandvideo.h" #include "SDL_waylandwindow.h" #include "color-management-v1-client-protocol.h" +#include "../../events/SDL_windowevents_c.h" typedef struct Wayland_ColorInfoState { struct wp_image_description_v1 *wp_image_description; struct wp_image_description_info_v1 *wp_image_description_info; - Wayland_ColorInfo *info; - bool result; + union + { + SDL_WindowData *window_data; + SDL_DisplayData *display_data; + }; + + enum + { + WAYLAND_COLOR_OBJECT_TYPE_WINDOW, + WAYLAND_COLOR_OBJECT_TYPE_DISPLAY + } object_type; + + SDL_HDROutputProperties HDR; + + // The ICC fd is only valid if the size is non-zero. + int icc_fd; + Uint32 icc_size; + + bool deferred_event_processing; } Wayland_ColorInfoState; +static void Wayland_CancelColorInfoRequest(Wayland_ColorInfoState *state) +{ + if (state) { + if (state->wp_image_description_info) { + wp_image_description_info_v1_destroy(state->wp_image_description_info); + state->wp_image_description_info = NULL; + } + if (state->wp_image_description) { + wp_image_description_v1_destroy(state->wp_image_description); + state->wp_image_description = NULL; + } + } +} + +void Wayland_FreeColorInfoState(Wayland_ColorInfoState *state) +{ + if (state) { + Wayland_CancelColorInfoRequest(state); + + switch (state->object_type) { + case WAYLAND_COLOR_OBJECT_TYPE_WINDOW: + state->window_data->color_info_state = NULL; + break; + case WAYLAND_COLOR_OBJECT_TYPE_DISPLAY: + state->display_data->color_info_state = NULL; + break; + } + + SDL_free(state); + } +} + static void image_description_info_handle_done(void *data, struct wp_image_description_info_v1 *wp_image_description_info_v1) { Wayland_ColorInfoState *state = (Wayland_ColorInfoState *)data; + Wayland_CancelColorInfoRequest(state); - if (state->wp_image_description_info) { - wp_image_description_info_v1_destroy(state->wp_image_description_info); - state->wp_image_description_info = NULL; + switch (state->object_type) { + case WAYLAND_COLOR_OBJECT_TYPE_WINDOW: + { + SDL_SetWindowHDRProperties(state->window_data->sdlwindow, &state->HDR, true); + if (state->icc_size) { + state->window_data->icc_fd = state->icc_fd; + state->window_data->icc_size = state->icc_size; + SDL_SendWindowEvent(state->window_data->sdlwindow, SDL_EVENT_WINDOW_ICCPROF_CHANGED, 0, 0); + } + } break; + case WAYLAND_COLOR_OBJECT_TYPE_DISPLAY: + { + SDL_copyp(&state->display_data->HDR, &state->HDR); + } break; } - if (state->wp_image_description) { - wp_image_description_v1_destroy(state->wp_image_description); - state->wp_image_description = NULL; - } - - state->result = true; } static void image_description_info_handle_icc_file(void *data, @@ -60,8 +116,8 @@ static void image_description_info_handle_icc_file(void *data, { Wayland_ColorInfoState *state = (Wayland_ColorInfoState *)data; - state->info->icc_fd = icc; - state->info->icc_size = icc_size; + state->icc_fd = icc; + state->icc_size = icc_size; } static void image_description_info_handle_primaries(void *data, @@ -102,7 +158,7 @@ static void image_description_info_handle_luminances(void *data, uint32_t reference_lum) { Wayland_ColorInfoState *state = (Wayland_ColorInfoState *)data; - state->info->HDR.HDR_headroom = (float)max_lum / (float)reference_lum; + state->HDR.HDR_headroom = (float)max_lum / (float)reference_lum; } static void image_description_info_handle_target_primaries(void *data, @@ -157,13 +213,18 @@ static void PumpColorspaceEvents(Wayland_ColorInfoState *state) // Run the image description sequence to completion in its own queue. struct wl_event_queue *queue = WAYLAND_wl_display_create_queue(vid->display); - WAYLAND_wl_proxy_set_queue((struct wl_proxy *)state->wp_image_description, queue); + if (state->deferred_event_processing) { + WAYLAND_wl_proxy_set_queue((struct wl_proxy *)state->wp_image_description_info, queue); + } else { + WAYLAND_wl_proxy_set_queue((struct wl_proxy *)state->wp_image_description, queue); + } while (state->wp_image_description) { WAYLAND_wl_display_dispatch_queue(vid->display, queue); } WAYLAND_wl_event_queue_destroy(queue); + Wayland_FreeColorInfoState(state); } static void image_description_handle_failed(void *data, @@ -172,9 +233,11 @@ static void image_description_handle_failed(void *data, const char *msg) { Wayland_ColorInfoState *state = (Wayland_ColorInfoState *)data; + Wayland_CancelColorInfoRequest(state); - wp_image_description_v1_destroy(state->wp_image_description); - state->wp_image_description = NULL; + if (state->deferred_event_processing) { + Wayland_FreeColorInfoState(state); + } } static void image_description_handle_ready(void *data, @@ -186,6 +249,10 @@ static void image_description_handle_ready(void *data, // This will inherit the queue of the factory image description object. state->wp_image_description_info = wp_image_description_v1_get_information(state->wp_image_description); wp_image_description_info_v1_add_listener(state->wp_image_description_info, &image_description_info_listener, data); + + if (state->deferred_event_processing) { + PumpColorspaceEvents(state); + } } static const struct wp_image_description_v1_listener image_description_listener = { @@ -193,32 +260,44 @@ static const struct wp_image_description_v1_listener image_description_listener image_description_handle_ready }; -bool Wayland_GetColorInfoForWindow(SDL_WindowData *window_data, Wayland_ColorInfo *info) +void Wayland_GetColorInfoForWindow(SDL_WindowData *window_data, bool defer_event_processing) { - Wayland_ColorInfoState state; - SDL_zero(state); - state.info = info; + // Cancel any pending request, as it is out-of-date. + Wayland_FreeColorInfoState(window_data->color_info_state); + Wayland_ColorInfoState *state = SDL_calloc(1, sizeof(Wayland_ColorInfoState)); - state.wp_image_description = wp_color_management_surface_feedback_v1_get_preferred(window_data->wp_color_management_surface_feedback); - wp_image_description_v1_add_listener(state.wp_image_description, &image_description_listener, &state); + if (state) { + window_data->color_info_state = state; + state->window_data = window_data; + state->object_type = WAYLAND_COLOR_OBJECT_TYPE_WINDOW; + state->deferred_event_processing = defer_event_processing; + state->wp_image_description = wp_color_management_surface_feedback_v1_get_preferred(window_data->wp_color_management_surface_feedback); + wp_image_description_v1_add_listener(state->wp_image_description, &image_description_listener, state); - PumpColorspaceEvents(&state); - - return state.result; + if (!defer_event_processing) { + PumpColorspaceEvents(state); + } + } } -bool Wayland_GetColorInfoForOutput(SDL_DisplayData *display_data, Wayland_ColorInfo *info) +void Wayland_GetColorInfoForOutput(SDL_DisplayData *display_data, bool defer_event_processing) { - Wayland_ColorInfoState state; - SDL_zero(state); - state.info = info; + // Cancel any pending request, as it is out-of-date. + Wayland_FreeColorInfoState(display_data->color_info_state); + Wayland_ColorInfoState *state = SDL_calloc(1, sizeof(Wayland_ColorInfoState)); - state.wp_image_description = wp_color_management_output_v1_get_image_description(display_data->wp_color_management_output); - wp_image_description_v1_add_listener(state.wp_image_description, &image_description_listener, &state); + if (state) { + display_data->color_info_state = state; + state->display_data = display_data; + state->object_type = WAYLAND_COLOR_OBJECT_TYPE_DISPLAY; + state->deferred_event_processing = defer_event_processing; + state->wp_image_description = wp_color_management_output_v1_get_image_description(display_data->wp_color_management_output); + wp_image_description_v1_add_listener(state->wp_image_description, &image_description_listener, state); - PumpColorspaceEvents(&state); - - return state.result; + if (!defer_event_processing) { + PumpColorspaceEvents(state); + } + } } #endif // SDL_VIDEO_DRIVER_WAYLAND diff --git a/src/video/wayland/SDL_waylandcolor.h b/src/video/wayland/SDL_waylandcolor.h index 6125374b85..bef5d8c3e0 100644 --- a/src/video/wayland/SDL_waylandcolor.h +++ b/src/video/wayland/SDL_waylandcolor.h @@ -26,16 +26,10 @@ #include "../SDL_sysvideo.h" -typedef struct Wayland_ColorInfo -{ - SDL_HDROutputProperties HDR; +struct Wayland_ColorInfoState; - // The ICC fd is only valid if the size is non-zero. - int icc_fd; - Uint32 icc_size; -} Wayland_ColorInfo; - -extern bool Wayland_GetColorInfoForWindow(SDL_WindowData *window_data, Wayland_ColorInfo *info); -extern bool Wayland_GetColorInfoForOutput(SDL_DisplayData *display_data, Wayland_ColorInfo *info); +extern void Wayland_FreeColorInfoState(struct Wayland_ColorInfoState *state); +extern void Wayland_GetColorInfoForWindow(SDL_WindowData *window_data, bool defer_event_processing); +extern void Wayland_GetColorInfoForOutput(SDL_DisplayData *display_data, bool defer_event_processing); #endif // SDL_waylandcolor_h_ diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c index 853c05eb1f..43019535f5 100644 --- a/src/video/wayland/SDL_waylandvideo.c +++ b/src/video/wayland/SDL_waylandvideo.c @@ -1118,21 +1118,12 @@ static const struct wl_output_listener output_listener = { display_handle_description // Version 4 }; -static void Wayland_GetOutputColorInfo(SDL_DisplayData *display) -{ - Wayland_ColorInfo info; - SDL_zero(info); - - if (Wayland_GetColorInfoForOutput(display, &info)) { - SDL_copyp(&display->HDR, &info.HDR); - } -} - static void handle_output_image_description_changed(void *data, struct wp_color_management_output_v1 *wp_color_management_output_v1) { + SDL_DisplayData *display = (SDL_DisplayData *)data; // wl_display.done is called after this event, so the display HDR status will be updated there. - Wayland_GetOutputColorInfo(data); + Wayland_GetColorInfoForOutput(display, false); } static const struct wp_color_management_output_v1_listener wp_color_management_output_listener = { @@ -1171,7 +1162,7 @@ static bool Wayland_add_display(SDL_VideoData *d, uint32_t id, uint32_t version) if (data->videodata->wp_color_manager_v1) { data->wp_color_management_output = wp_color_manager_v1_get_output(data->videodata->wp_color_manager_v1, output); wp_color_management_output_v1_add_listener(data->wp_color_management_output, &wp_color_management_output_listener, data); - Wayland_GetOutputColorInfo(data); + Wayland_GetColorInfoForOutput(data, true); } return true; } @@ -1191,6 +1182,7 @@ static void Wayland_free_display(SDL_VideoDisplay *display, bool send_event) SDL_free(display_data->wl_output_name); if (display_data->wp_color_management_output) { + Wayland_FreeColorInfoState(display_data->color_info_state); wp_color_management_output_v1_destroy(display_data->wp_color_management_output); } @@ -1221,7 +1213,7 @@ static void Wayland_FinalizeDisplays(SDL_VideoData *vid) static void Wayland_init_xdg_output(SDL_VideoData *d) { - for(int i = 0; i < d->output_count; ++i) { + for (int i = 0; i < d->output_count; ++i) { SDL_DisplayData *disp = d->output_list[i]; disp->xdg_output = zxdg_output_manager_v1_get_xdg_output(disp->videodata->xdg_output_manager, disp->output); zxdg_output_v1_add_listener(disp->xdg_output, &xdg_output_listener, disp); @@ -1234,7 +1226,7 @@ static void Wayland_InitColorManager(SDL_VideoData *d) SDL_DisplayData *disp = d->output_list[i]; disp->wp_color_management_output = wp_color_manager_v1_get_output(disp->videodata->wp_color_manager_v1, disp->output); wp_color_management_output_v1_add_listener(disp->wp_color_management_output, &wp_color_management_output_listener, disp); - Wayland_GetOutputColorInfo(disp); + Wayland_GetColorInfoForOutput(disp, true); } } diff --git a/src/video/wayland/SDL_waylandvideo.h b/src/video/wayland/SDL_waylandvideo.h index 5b5ee24c0f..8cde64c9ac 100644 --- a/src/video/wayland/SDL_waylandvideo.h +++ b/src/video/wayland/SDL_waylandvideo.h @@ -118,6 +118,7 @@ struct SDL_DisplayData SDL_DisplayID display; SDL_VideoDisplay placeholder; int wl_output_done_count; + struct Wayland_ColorInfoState *color_info_state; }; // Needed here to get wl_surface declaration, fixes GitHub#4594 diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c index c06f72ad0a..212fd54f35 100644 --- a/src/video/wayland/SDL_waylandwindow.c +++ b/src/video/wayland/SDL_waylandwindow.c @@ -1656,17 +1656,7 @@ static void feedback_surface_preferred_changed(void *data, uint32_t identity) { SDL_WindowData *wind = (SDL_WindowData *)data; - Wayland_ColorInfo info; - SDL_zero(info); - - if (Wayland_GetColorInfoForWindow(wind, &info)) { - SDL_SetWindowHDRProperties(wind->sdlwindow, &info.HDR, true); - if (info.icc_size) { - wind->icc_fd = info.icc_fd; - wind->icc_size = info.icc_size; - SDL_SendWindowEvent(wind->sdlwindow, SDL_EVENT_WINDOW_ICCPROF_CHANGED, 0, 0); - } - } + Wayland_GetColorInfoForWindow(wind, false); } static const struct wp_color_management_surface_feedback_v1_listener color_management_surface_feedback_listener = { @@ -2626,6 +2616,7 @@ bool Wayland_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Proper if (c->wp_color_manager_v1) { data->wp_color_management_surface_feedback = wp_color_manager_v1_get_surface_feedback(c->wp_color_manager_v1, data->surface); wp_color_management_surface_feedback_v1_add_listener(data->wp_color_management_surface_feedback, &color_management_surface_feedback_listener, data); + Wayland_GetColorInfoForWindow(data, true); } else if (c->frog_color_management_factory_v1) { data->frog_color_managed_surface = frog_color_management_factory_v1_get_color_managed_surface(c->frog_color_management_factory_v1, data->surface); frog_color_managed_surface_add_listener(data->frog_color_managed_surface, &frog_surface_listener, data); @@ -3092,6 +3083,7 @@ void Wayland_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window) } if (wind->wp_color_management_surface_feedback) { + Wayland_FreeColorInfoState(wind->color_info_state); wp_color_management_surface_feedback_v1_destroy(wind->wp_color_management_surface_feedback); } diff --git a/src/video/wayland/SDL_waylandwindow.h b/src/video/wayland/SDL_waylandwindow.h index 601589a2d3..619fd79e6d 100644 --- a/src/video/wayland/SDL_waylandwindow.h +++ b/src/video/wayland/SDL_waylandwindow.h @@ -118,6 +118,8 @@ struct SDL_WindowData struct frog_color_managed_surface *frog_color_managed_surface; struct wp_color_management_surface_feedback_v1 *wp_color_management_surface_feedback; + struct Wayland_ColorInfoState *color_info_state; + SDL_AtomicInt swap_interval_ready; SDL_DisplayData **outputs;