Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions plugins/common/workspace-wall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ class workspace_wall_t::workspace_wall_node_t : public scene::node_t
aux_buffers[i][j].allocate(wf::dimensions(bbox), wall->output->handle->scale,
wf::buffer_allocation_hints_t{
.needs_alpha = false,
.hdr_linear = wall->output && wall->output->is_hdr(),
});
aux_buffer_damage[i][j] |= bbox;
aux_buffer_current_scale[i][j] = 1.0;
Expand Down
5 changes: 4 additions & 1 deletion plugins/cube/cube.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,14 @@ class wayfire_cube : public wf::per_output_plugin_instance_t, public wf::pointer

damage ^= bbox;

const bool is_hdr = self->cube->output && self->cube->output->is_hdr();

for (int i = 0; i < (int)ws_instances.size(); i++)
{
const float scale = self->cube->output->handle->scale;
auto bbox = self->workspaces[i]->get_bounding_box();
framebuffers[i].allocate(wf::dimensions(bbox), scale);
framebuffers[i].allocate(wf::dimensions(bbox), scale,
wf::buffer_allocation_hints_t{.hdr_linear = is_hdr});

wf::render_target_t target{framebuffers[i]};
target.geometry = self->workspaces[i]->get_bounding_box();
Expand Down
3 changes: 2 additions & 1 deletion plugins/grid/wayfire/plugins/crossfade.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ class crossfade_node_t : public scene::view_2d_transformer_t
const wf::geometry_t bbox = root_node->get_bounding_box();
const wf::geometry_t g = view->get_geometry();
const float scale = view->get_output()->handle->scale;
original_buffer.allocate(wf::dimensions(g), scale);
original_buffer.allocate(wf::dimensions(g), scale,
wf::buffer_allocation_hints_t{.hdr_linear = view->get_output() && view->get_output()->is_hdr()});

wf::render_target_t target{original_buffer};
target.geometry = view->get_geometry();
Expand Down
3 changes: 3 additions & 0 deletions src/api/wayfire/core.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,9 @@ class compositor_core_t : public wf::object_base_t, public signal::provider_t
wlr_xdg_foreign_v2 *foreign_v2;

wlr_ext_data_control_manager_v1 *ext_data_control;

wlr_color_manager_v1 *color_manager_v1 = NULL;
wlr_color_representation_manager_v1 *color_representation_v1 = NULL;
} protocols;

std::string to_string() const
Expand Down
2 changes: 2 additions & 0 deletions src/api/wayfire/nonstd/wlroots.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ extern "C"
struct wlr_viewporter;

struct wlr_ext_data_control_manager_v1;
struct wlr_color_manager_v1;
struct wlr_color_representation_manager_v1;

#include <wlr/types/wlr_input_device.h>
#include <wlr/types/wlr_pointer.h>
Expand Down
12 changes: 12 additions & 0 deletions src/api/wayfire/output.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,18 @@ class output_t : public wf::object_base_t, public wf::signal::provider_t
virtual void add_axis(option_sptr_t<keybinding_t> axis, wf::axis_callback*) = 0;
virtual void add_button(option_sptr_t<buttonbinding_t> button, wf::button_callback*) = 0;
virtual void add_activator(option_sptr_t<activatorbinding_t> activator, wf::activator_callback*) = 0;
/**
* Check whether the output is currently driving an HDR (ST2084 PQ) image description.
*
* Plugins keep their linear-space auxilliary buffers in the SDR-relative linear domain
* (target_tf == EXT_LINEAR). On HDR (PQ) outputs, HDR sources contribute SDR-relative linear
* values up to ~49.26 (PQ peak / SDR reference white), which would be clipped or quantized by
* an 8-bit linear backing. Plugins use this hint to request FP16 storage
* (@buffer_allocation_hints_t::hdr_linear) for such intermediates.
*
* Returns false when no image description has been negotiated.
*/
bool is_hdr() const;

/**
* Remove all bindings which have the given callback, regardless of the type.
Expand Down
50 changes: 49 additions & 1 deletion src/api/wayfire/render.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ namespace wf
{
class output_t;
struct auxilliary_buffer_t;

Comment thread
kode54 marked this conversation as resolved.
namespace vk
{
class command_buffer_t;
Expand Down Expand Up @@ -52,10 +53,33 @@ struct color_transform_t
*/
wlr_color_range color_range = WLR_COLOR_RANGE_NONE;

/**
* Alpha mode of the texture, as set via wp_color_representation_v1. The default
* (premultiplied electrical) matches the wlroots renderer's compositing model. Other modes
* are not currently forwarded to the renderer.
*/
wlr_alpha_mode alpha_mode = WLR_COLOR_ALPHA_MODE_PREMULTIPLIED_ELECTRICAL;

/**
* Chroma sample location, as set via wp_color_representation_v1. Used only for ycbcr textures.
* Not currently forwarded to the renderer.
*/
wlr_color_chroma_location chroma_location = WLR_COLOR_CHROMA_LOCATION_NONE;

bool operator ==(const color_transform_t& other) const;
bool operator !=(const color_transform_t& other) const;
};

/**
* Compute the luminance multiplier needed when a texture with @source_tf is rendered to a
* target with @target_tf. The wlroots renderer does no implicit luminance scaling between
* SDR and HDR domains, so SDR content composited onto a PQ output (or vice-versa) needs
* an explicit factor to bridge the [0,1]-relative SDR linear range and the 0–10000 cd/m²
* absolute PQ linear range. Returns 1.0f when no bridging is needed.
*/
float compute_luminance_multiplier(wlr_color_transfer_function source_tf,
wlr_color_transfer_function target_tf);

/**
* A wrapper around wlr_texture which ensures that the texture is kept alive as long as the wrapper object
* is alive.
Expand Down Expand Up @@ -237,6 +261,13 @@ struct render_buffer_t
struct buffer_allocation_hints_t
{
bool needs_alpha = true;
/**
* If set, prefer a half-float (FP16) per-channel format so the buffer can store
* extended-range linear values without clipping or banding. Used for HDR linear
* compositing intermediates. Falls back to a 16-bit fixed format and then to 8-bit
* if no FP16 format is available.
*/
bool hdr_linear = false;
Comment thread
kode54 marked this conversation as resolved.
};

/**
Expand Down Expand Up @@ -424,11 +455,28 @@ struct render_target_t : public render_buffer_t

/**
* Set a new color transform for the render target.
*
* @param transform The wlr_color_transform to apply when rendering to this target. Wayfire
* takes a reference; the caller retains ownership of its own reference.
* @param target_tf The transfer function that the @transform encodes to. Used to compute
* per-texture luminance multipliers when SDR content is rendered to HDR targets and vice
* versa.
*/
void set_color_transform(wlr_color_transform *transform);
void set_color_transform(wlr_color_transform *transform,
wlr_color_transfer_function target_tf = WLR_COLOR_TRANSFER_FUNCTION_SRGB);

/**
* The transfer function that the render target's color transform encodes to. Read this to
* determine whether the target is HDR (ST2084_PQ) or SDR.
*/
wlr_color_transfer_function get_output_transfer_function() const
{
return output_transfer_function;
}

private:
wlr_color_transform *inverse_eotf = nullptr;
wlr_color_transfer_function output_transfer_function = WLR_COLOR_TRANSFER_FUNCTION_SRGB;
void copy_from(const render_target_t& other);
};

Expand Down
1 change: 1 addition & 0 deletions src/api/wayfire/unstable/wlr-surface-node.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ class wlr_surface_node_t : public node_t, public zero_copy_texturable_node_t
void handle_enter(wf::output_t *output);
void handle_leave(wf::output_t *output);
void update_pending_outputs();
void update_preferred_image_description();
wf::wl_idle_call idle_update_outputs;

wf::wl_listener_wrapper on_surface_destroyed;
Expand Down
10 changes: 8 additions & 2 deletions src/api/wayfire/view-transform.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,14 @@ class transformer_base_node_t : public scene::floating_inner_node_t
// children's current content.
wf::region_t cached_damage;

/**
* @param output Optional. When provided, the inner buffer will be allocated with
* the @hdr_linear hint if the output is currently in an HDR (PQ) configuration,
* so HDR contents above SDR reference white aren't clipped or banded by an
* 8-bit linear backing.
*/
std::shared_ptr<wf::texture_t> get_updated_contents(const wf::geometry_t& bbox, float scale,
std::vector<scene::render_instance_uptr>& children);
std::vector<scene::render_instance_uptr>& children, wf::output_t *output = nullptr);

void release_buffers();
~transformer_base_node_t();
Expand Down Expand Up @@ -134,7 +140,7 @@ class transformer_render_instance_t : public render_instance_t
return tex;
}

return self->get_updated_contents(self->get_children_bounding_box(), scale, children);
return self->get_updated_contents(self->get_children_bounding_box(), scale, children, _shown_on);
}

void presentation_feedback(wf::output_t *output) override
Expand Down
41 changes: 40 additions & 1 deletion src/core/core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,46 @@ void wf::compositor_core_impl_t::init()

wlr_fractional_scale_manager_v1_create(display, 1);
wlr_single_pixel_buffer_manager_v1_create(display);
wlr_color_representation_manager_v1_create_with_renderer(display, 1, renderer);
protocols.color_representation_v1 =
wlr_color_representation_manager_v1_create_with_renderer(display, 1, renderer);

if (renderer->features.input_color_transform)
{
static const enum wp_color_manager_v1_render_intent render_intents[] = {
WP_COLOR_MANAGER_V1_RENDER_INTENT_PERCEPTUAL,
};

size_t transfer_functions_len = 0;
enum wp_color_manager_v1_transfer_function *transfer_functions =
wlr_color_manager_v1_transfer_function_list_from_renderer(renderer, &transfer_functions_len);

size_t primaries_len = 0;
enum wp_color_manager_v1_primaries *primaries =
wlr_color_manager_v1_primaries_list_from_renderer(renderer, &primaries_len);

wlr_color_manager_v1_options cm_options{};
cm_options.features.parametric = true;
cm_options.features.set_mastering_display_primaries = true;
cm_options.render_intents = render_intents;
cm_options.render_intents_len = sizeof(render_intents) / sizeof(render_intents[0]);
cm_options.transfer_functions = transfer_functions;
cm_options.transfer_functions_len = transfer_functions_len;
cm_options.primaries = primaries;
cm_options.primaries_len = primaries_len;

protocols.color_manager_v1 = wlr_color_manager_v1_create(display, 2, &cm_options);
if (!protocols.color_manager_v1)
{
LOGE("Failed to create wlr_color_manager_v1 global");
}

free(transfer_functions);
free(primaries);
} else
{
LOGI("Renderer does not support input color transforms; "
"wp_color_management_v1 will not be available.");
}

this->bindings = std::make_unique<bindings_repository_t>();
image_io::init();
Expand Down
10 changes: 9 additions & 1 deletion src/core/output-layout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -873,7 +873,6 @@ struct output_layout_output_t
{
LOGC(OUTPUT, "Disabling HDR on output ", handle->name);
wlr_output_state_set_image_description(&pending_state.pending, NULL);
pending_state.commit(handle);
} else
{
LOGC(OUTPUT, "Enabling HDR on output ", handle->name);
Expand All @@ -888,6 +887,15 @@ struct output_layout_output_t
wlr_output_state_set_image_description(&pending_state.pending, &image_desc);
}

// wlroots' set_image_description doesn't trigger empty-buffer allocation or set
// allow_reconfiguration, so re-pin the current render format and request a
// reconfiguration. That forces wlroots to attach a fresh primary buffer and the
// DRM backend to set DRM_MODE_ATOMIC_ALLOW_MODESET, which amdgpu requires for
// HDR_OUTPUT_METADATA changes.
wlr_output_state_set_render_format(&pending_state.pending, handle->render_format);
pending_state.pending.allow_reconfiguration = true;
pending_state.commit(handle);

current_hdr_enabled = want_hdr_enabled;
}

Expand Down
11 changes: 11 additions & 0 deletions src/output/output.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,17 @@ void wf::output_impl_t::rem_binding(void *callback)
remove_binding(activator_map, (activator_callback*)callback);
}

static bool is_hdr_transfer_function(wlr_color_transfer_function tf)
{
return tf == WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ;
}

bool wf::output_t::is_hdr() const
{
const auto *img_desc = this->handle->image_description;
return img_desc && is_hdr_transfer_function(img_desc->transfer_function);
}

wayfire_view get_active_view_for_output(wf::output_t *output)
{
if (output == wf::get_core().seat->get_active_output())
Expand Down
Loading
Loading