aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/wlr/types/wlr_scene.h9
-rw-r--r--types/scene/wlr_scene.c101
2 files changed, 77 insertions, 33 deletions
diff --git a/include/wlr/types/wlr_scene.h b/include/wlr/types/wlr_scene.h
index 87cf4fc9..c1b6f130 100644
--- a/include/wlr/types/wlr_scene.h
+++ b/include/wlr/types/wlr_scene.h
@@ -39,6 +39,7 @@ struct wlr_scene_buffer;
struct wlr_presentation;
struct wlr_linux_dmabuf_v1;
+struct wlr_output_state;
typedef bool (*wlr_scene_buffer_point_accepts_input_func_t)(
struct wlr_scene_buffer *buffer, int sx, int sy);
@@ -444,10 +445,18 @@ void wlr_scene_output_destroy(struct wlr_scene_output *scene_output);
*/
void wlr_scene_output_set_position(struct wlr_scene_output *scene_output,
int lx, int ly);
+
/**
* Render and commit an output.
*/
bool wlr_scene_output_commit(struct wlr_scene_output *scene_output);
+
+/**
+ * Render and populate given output state.
+ */
+bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
+ struct wlr_output_state *state);
+
/**
* Call wlr_surface_send_frame_done() on all surfaces in the scene rendered by
* wlr_scene_output_commit() for which wlr_scene_surface.primary_output
diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c
index ae4557f8..b4d16056 100644
--- a/types/scene/wlr_scene.c
+++ b/types/scene/wlr_scene.c
@@ -14,6 +14,7 @@
#include <wlr/util/log.h>
#include <wlr/util/region.h>
#include "types/wlr_buffer.h"
+#include "types/wlr_output.h"
#include "types/wlr_scene.h"
#include "util/array.h"
#include "util/env.h"
@@ -1464,7 +1465,7 @@ static void scene_buffer_send_dmabuf_feedback(const struct wlr_scene *scene,
}
static bool scene_buffer_can_consider_direct_scanout(struct wlr_scene_buffer *buffer,
- const struct render_data *data) {
+ struct wlr_output_state *state, const struct render_data *data) {
const struct wlr_scene_output *scene_output = data->output;
struct wlr_scene_node *node = &buffer->node;
@@ -1483,6 +1484,11 @@ static bool scene_buffer_can_consider_direct_scanout(struct wlr_scene_buffer *bu
return false;
}
+ if (state->committed & (WLR_OUTPUT_STATE_MODE | WLR_OUTPUT_STATE_ENABLED)) {
+ // Legacy DRM will explode if we try to modeset with a direct scanout buffer
+ return false;
+ }
+
if (!wlr_output_is_direct_scanout_allowed(scene_output->output)) {
return false;
}
@@ -1517,41 +1523,59 @@ static bool scene_buffer_can_consider_direct_scanout(struct wlr_scene_buffer *bu
}
static bool scene_buffer_try_direct_scanout(struct wlr_scene_buffer *buffer,
- struct wlr_scene_output *scene_output) {
- struct wlr_output_state state = {
- .committed = WLR_OUTPUT_STATE_BUFFER,
- .buffer = buffer->buffer,
- };
+ struct wlr_scene_output *scene_output, struct wlr_output_state *state) {
+ wlr_output_state_set_buffer(state, buffer->buffer);
+
+ pixman_region32_t frame_damage;
+ get_frame_damage(scene_output, &frame_damage);
+ wlr_output_state_set_damage(state, &frame_damage);
+ pixman_region32_fini(&frame_damage);
+
+ if (!wlr_output_test_state(scene_output->output, state)) {
+ // reset buffer and damage
+ state->committed &= ~(WLR_OUTPUT_STATE_BUFFER | WLR_OUTPUT_STATE_DAMAGE);
+ wlr_buffer_unlock(state->buffer);
+ pixman_region32_fini(&state->damage);
- if (!wlr_output_test_state(scene_output->output, &state)) {
return false;
}
wl_signal_emit_mutable(&buffer->events.output_present, scene_output);
+ return true;
+}
- state.committed |= WLR_OUTPUT_STATE_DAMAGE;
- get_frame_damage(scene_output, &state.damage);
- bool ok = wlr_output_commit_state(scene_output->output, &state);
- pixman_region32_fini(&state.damage);
- if (!ok) {
+bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) {
+ if (!scene_output->output->needs_frame && !pixman_region32_not_empty(
+ &scene_output->damage_ring.current)) {
+ return true;
+ }
+
+ struct wlr_output_state state = {0};
+ if (!wlr_scene_output_build_state(scene_output, &state)) {
return false;
}
- wlr_damage_ring_rotate(&scene_output->damage_ring);
+ bool success = wlr_output_commit_state(scene_output->output, &state);
+ wlr_output_state_finish(&state);
- return true;
+ if (success) {
+ wlr_damage_ring_rotate(&scene_output->damage_ring);
+ }
+
+ return success;
}
-bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) {
+bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
+ struct wlr_output_state *state) {
+ if ((state->committed & WLR_OUTPUT_STATE_ENABLED) && !state->enabled) {
+ // if the state is being disabled, do nothing.
+ return true;
+ }
+
struct wlr_output *output = scene_output->output;
enum wlr_scene_debug_damage_option debug_damage =
scene_output->scene->debug_damage_option;
- if (!output->needs_frame && !pixman_region32_not_empty(
- &scene_output->damage_ring.current)) {
- return true;
- }
-
struct render_data render_data = {
.transform = output->transform,
.scale = output->scale,
@@ -1559,9 +1583,26 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) {
.output = scene_output,
};
- wlr_output_effective_resolution(output,
+ output_pending_resolution(output, state,
&render_data.logical.width, &render_data.logical.height);
+ if (state->committed & WLR_OUTPUT_STATE_TRANSFORM) {
+ render_data.transform = state->transform;
+ }
+
+ if (state->committed & WLR_OUTPUT_STATE_SCALE) {
+ render_data.scale = state->scale;
+ }
+
+ if (render_data.transform & WL_OUTPUT_TRANSFORM_90) {
+ int tmp = render_data.logical.width;
+ render_data.logical.width = render_data.logical.height;
+ render_data.logical.height = tmp;
+ }
+
+ render_data.logical.width /= render_data.scale;
+ render_data.logical.height /= render_data.scale;
+
struct render_list_constructor_data list_con = {
.box = render_data.logical,
.render_list = &scene_output->render_list,
@@ -1587,7 +1628,7 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) {
if (node->type == WLR_SCENE_NODE_BUFFER) {
struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node);
- if (scene_buffer_can_consider_direct_scanout(buffer, &render_data)) {
+ if (scene_buffer_can_consider_direct_scanout(buffer, state, &render_data)) {
if (buffer->primary_output == scene_output) {
struct wlr_linux_dmabuf_feedback_v1_init_options options = {
.main_renderer = output->renderer,
@@ -1598,7 +1639,7 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) {
sent_direct_scanout_feedback = true;
}
- scanout = scene_buffer_try_direct_scanout(buffer, scene_output);
+ scanout = scene_buffer_try_direct_scanout(buffer, scene_output, state);
}
}
}
@@ -1660,7 +1701,7 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) {
pixman_region32_fini(&acc_damage);
}
- if (!wlr_output_configure_primary_swapchain(output, NULL, &output->swapchain)) {
+ if (!wlr_output_configure_primary_swapchain(output, state, &output->swapchain)) {
return false;
}
@@ -1770,26 +1811,20 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) {
return false;
}
- wlr_output_attach_buffer(output, buffer);
+ wlr_output_state_set_buffer(state, buffer);
wlr_buffer_unlock(buffer);
pixman_region32_t frame_damage;
get_frame_damage(scene_output, &frame_damage);
- wlr_output_set_damage(output, &frame_damage);
+ wlr_output_state_set_damage(state, &frame_damage);
pixman_region32_fini(&frame_damage);
- bool success = wlr_output_commit(output);
-
- if (success) {
- wlr_damage_ring_rotate(&scene_output->damage_ring);
- }
-
if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT &&
!wl_list_empty(&scene_output->damage_highlight_regions)) {
wlr_output_schedule_frame(scene_output->output);
}
- return success;
+ return true;
}
static void scene_node_send_frame_done(struct wlr_scene_node *node,