--- a/plugins/cube/cube.cpp +++ b/plugins/cube/cube.cpp @@ -145,14 +145,23 @@ std::vector& instructions, const wf::render_target_t& target, wf::regionf_t& damage) override { + auto bbox = self->get_bounding_box(); + auto our_damage = damage & bbox; + if (our_damage.empty()) + { + return; + } + + // The cube renders in output-local coordinates, including its + // damage. Never repaint pixels occluded by a higher layer. + our_damage += -wf::origin(bbox); instructions.push_back(wf::scene::render_instruction_t{ .instance = this, - .target = target.translated(-wf::origin(self->get_bounding_box())), - .damage = damage & self->get_bounding_box(), + .target = target.translated(-wf::origin(bbox)), + .damage = our_damage, }); - wf::regionf_t background_damage = - output_background->get_bounding_box(); + wf::regionf_t background_damage = our_damage; auto background_target = target.translated(-wf::origin(self->get_bounding_box())); for (auto& instance : output_background_instances) @@ -161,15 +170,22 @@ instructions, background_target, background_damage); } - auto bbox = self->get_bounding_box(); - damage ^= bbox; 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); + if (framebuffers[i].allocate(wf::dimensions(bbox), scale) == + wf::buffer_reallocation_result_t::REALLOCATED) + { + ws_damage[i] |= bbox; + } + + if (ws_damage[i].empty()) + { + continue; + } wf::render_target_t target{framebuffers[i]}; target.geometry = self->workspaces[i]->get_bounding_box(); @@ -177,14 +193,14 @@ wf::render_pass_params_t params; params.instances = &ws_instances[i]; - params.damage = self->workspaces[i]->get_bounding_box(); + params.damage = ws_damage[i]; params.reference_output = self->cube->output; params.target = target; params.background_color = wf::color_t{0.0, 0.0, 0.0, 0.0}; params.flags = wf::RPASS_CLEAR_BACKGROUND | wf::RPASS_EMIT_SIGNALS; + ws_damage[i].clear(); wf::render_pass_t::run(params); - ws_damage[i].clear(); } } @@ -532,11 +548,12 @@ input_is_grabbed = false; } - void add_cube_render_node() + void add_desktop_render_node(const wf::scene::node_ptr& node, + const wf::scene::node_ptr& before = nullptr) { auto root = wf::get_core().scene(); auto children = root->get_children(); - auto overlay_layer = + auto anchor = before ? before : root->layers[(int)wf::scene::layer::OVERLAY]; std::vector updated; @@ -544,9 +561,9 @@ bool inserted = false; for (auto& child : children) { - if (!inserted && (child == overlay_layer)) - { - updated.push_back(render_node); + if (!inserted && (child == anchor)) + { + updated.push_back(node); inserted = true; } @@ -555,11 +572,18 @@ if (!inserted) { - updated.insert(updated.begin(), render_node); + // The built-in overlay layer is always present. Do not place + // desktop content above screensavers or locks if that changes. + updated.push_back(node); } root->set_children_list(updated); wf::scene::update(root, wf::scene::update_flag::CHILDREN_LIST); + } + + void add_cube_render_node() + { + add_desktop_render_node(render_node); } void rebuild_cube_render_node() @@ -705,7 +729,7 @@ fixed_overlay_node = std::make_shared(); fixed_overlay_node->set_children_list({overlay}); fixed_overlay_node->set_offset(wf::origin(output->get_layout_geometry())); - wf::scene::add_front(wf::get_core().scene(), fixed_overlay_node); + add_desktop_render_node(fixed_overlay_node, render_node); } /* Tries to initialize renderer, activate plugin, etc. */ @@ -1027,7 +1051,6 @@ load_program(); } - GL_CALL(glClear(GL_DEPTH_BUFFER_BIT)); /* The fixed output background is scheduled behind the cube. */ auto vp = calculate_vp_matrix(data.target); @@ -1070,8 +1093,12 @@ GL_CALL(glEnable(GL_BLEND)); GL_CALL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); GL_CALL(glEnable(GL_CULL_FACE)); - render_cube(GL_CCW, buffers); - render_cube(GL_CW, buffers); + wf::gles::for_each_scissor_rect(data.target, data.damage, [&] + { + GL_CALL(glClear(GL_DEPTH_BUFFER_BIT)); + render_cube(GL_CCW, buffers); + render_cube(GL_CW, buffers); + }); GL_CALL(glDisable(GL_CULL_FACE)); GL_CALL(glDisable(GL_BLEND)); @@ -1080,13 +1107,21 @@ }); } + bool animation_was_running = false; wf::effect_hook_t pre_hook = [=] () { update_view_matrix(); - wf::scene::damage_node(render_node, render_node->get_bounding_box()); - if (animation.cube_animation.running()) - { - output->render->damage_whole(); + const bool running = animation.cube_animation.running(); + if (render_node && (running || animation_was_running)) + { + // Repaint moving geometry and its final settled frame. At rest, + // workspace/background damage already schedules the needed frames. + wf::scene::damage_node(render_node, render_node->get_bounding_box()); + } + + animation_was_running = running; + if (running) + { output->render->schedule_redraw(); } else if (animation.in_exit) { @@ -1099,8 +1134,6 @@ clear_fixed_workspace_overlay(); rebuild_cube_render_node(); } - - output->render->schedule_redraw(); } };