diff options
| -rw-r--r-- | include/wlr/types/wlr_scene.h | 9 | ||||
| -rw-r--r-- | types/scene/wlr_scene.c | 91 | 
2 files changed, 88 insertions, 12 deletions
diff --git a/include/wlr/types/wlr_scene.h b/include/wlr/types/wlr_scene.h index 4c1f5ea9..033d4cc6 100644 --- a/include/wlr/types/wlr_scene.h +++ b/include/wlr/types/wlr_scene.h @@ -304,6 +304,15 @@ void wlr_scene_buffer_set_buffer(struct wlr_scene_buffer *scene_buffer,  	struct wlr_buffer *buffer);  /** + * Sets the buffer's backing buffer with a custom damage region. + * + * The damage region is in buffer-local coordinates. If the region is NULL, + * the whole buffer node will be damaged. + */ +void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buffer, +	struct wlr_buffer *buffer, pixman_region32_t *region); + +/**   * Set the source rectangle describing the region of the buffer which will be   * sampled to render this node. This allows cropping the buffer.   * diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 5c110c3a..96b70df5 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -420,27 +420,94 @@ struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_node *parent,  	return scene_buffer;  } -void wlr_scene_buffer_set_buffer(struct wlr_scene_buffer *scene_buffer, -		struct wlr_buffer *buffer)  { -	if (buffer == scene_buffer->buffer) { +void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buffer, +		struct wlr_buffer *buffer, pixman_region32_t *damage) { +	// specifying a region for a NULL buffer doesn't make sense. We need to know +	// about the buffer to scale the buffer local coordinates down to scene +	// coordinates.  +	assert(buffer || !damage); + +	if (buffer != scene_buffer->buffer) { +		if (!damage) { +			scene_node_damage_whole(&scene_buffer->node); +		} + +		wlr_texture_destroy(scene_buffer->texture); +		scene_buffer->texture = NULL; +		wlr_buffer_unlock(scene_buffer->buffer); + +		if (buffer) { +			scene_buffer->buffer = wlr_buffer_lock(buffer); +		} else { +			scene_buffer->buffer = NULL; +		} + +		scene_node_update_outputs(&scene_buffer->node); + +		if (!damage) { +			scene_node_damage_whole(&scene_buffer->node); +		} +	} + +	if (!damage) {  		return;  	} -	scene_node_damage_whole(&scene_buffer->node); +	int lx, ly; +	if (!wlr_scene_node_coords(&scene_buffer->node, &lx, &ly)) { +		return; +	} -	wlr_texture_destroy(scene_buffer->texture); -	scene_buffer->texture = NULL; -	wlr_buffer_unlock(scene_buffer->buffer); +	struct wlr_fbox box = scene_buffer->src_box; +	if (wlr_fbox_empty(&box)) { +		box.x = 0; +		box.y = 0; -	if (buffer) { -		scene_buffer->buffer = wlr_buffer_lock(buffer); +		if (scene_buffer->transform & WL_OUTPUT_TRANSFORM_90) { +			box.width = buffer->height; +			box.height = buffer->width; +		} else { +			box.width = buffer->width; +			box.height = buffer->height; +		} +	} + +	double scale_x, scale_y; +	if (scene_buffer->dst_width || scene_buffer->dst_height) { +		scale_x = scene_buffer->dst_width / box.width; +		scale_y = scene_buffer->dst_height / box.height;  	} else { -		scene_buffer->buffer = NULL; +		scale_x = buffer->width / box.width; +		scale_y = buffer->height / box.height;  	} -	scene_node_damage_whole(&scene_buffer->node); +	pixman_region32_t trans_damage; +	pixman_region32_init(&trans_damage); +	wlr_region_transform(&trans_damage, damage, +		scene_buffer->transform, buffer->width, buffer->height); +	pixman_region32_intersect_rect(&trans_damage, &trans_damage, +		box.x, box.y, box.width, box.height); -	scene_node_update_outputs(&scene_buffer->node); +	struct wlr_scene *scene = scene_node_get_root(&scene_buffer->node); +	struct wlr_scene_output *scene_output; +	wl_list_for_each(scene_output, &scene->outputs, link) { +		float output_scale = scene_output->output->scale; +		pixman_region32_t output_damage; +		pixman_region32_init(&output_damage); +		wlr_region_scale_xy(&output_damage, &trans_damage, +			output_scale * scale_x, output_scale * scale_y); +		pixman_region32_translate(&output_damage, +			(lx - scene_output->x) * output_scale, (ly - scene_output->y) * output_scale); +		wlr_output_damage_add(scene_output->damage, &output_damage); +		pixman_region32_fini(&output_damage); +	} + +	pixman_region32_fini(&trans_damage); +} + +void wlr_scene_buffer_set_buffer(struct wlr_scene_buffer *scene_buffer, +		struct wlr_buffer *buffer)  { +	wlr_scene_buffer_set_buffer_with_damage(scene_buffer, buffer, NULL);  }  void wlr_scene_buffer_set_source_box(struct wlr_scene_buffer *scene_buffer,  | 
