diff --git a/plugins/common/wayfire/plugins/common/workspace-wall.hpp b/plugins/common/wayfire/plugins/common/workspace-wall.hpp index 7130d1e53..ef49df8a8 100644 --- a/plugins/common/wayfire/plugins/common/workspace-wall.hpp +++ b/plugins/common/wayfire/plugins/common/workspace-wall.hpp @@ -290,7 +290,18 @@ class workspace_wall_t : public wf::signal::provider_t } } - void consider_rescale_workspace_buffer(int i, int j) + static int damage_sum_area(const wf::region_t& damage) + { + int sum = 0; + for (const auto& rect : damage) + { + sum += (rect.y2 - rect.y1) * (rect.x2 - rect.x1); + } + + return sum; + } + + bool consider_rescale_workspace_buffer(int i, int j, wf::region_t& visible_damage) { // In general, when rendering the auxilliary buffers for each workspace, we can render the // workspace thumbnails in a lower resolution, because at the end they are shown scaled. @@ -311,19 +322,16 @@ class workspace_wall_t : public wf::signal::provider_t // Avoid keeping a low resolution if we are going up in the scale (for example, expo exit // animation) and we're close to the 1.0 scale. Otherwise, we risk popping artifacts as we // suddenly switch from low to high resolution. - const bool scale_nearly_1 = (render_scale > 0.9) && (render_scale > current_scale); + const bool rescale_magnification = (render_scale > 0.5) && (render_scale > current_scale * 1.1); // In general, it is worth changing the buffer scale if we have a lot of damage to the old // buffer, so that for ex. a full re-scale is actually cheaper than repaiting the old buffer. // This could easily happen for example if we have a video player during Expo start animation. - const auto damage_extents = self->aux_buffer_damage[i][j].get_extents(); const int repaint_cost_current_scale = - ((damage_extents.x2 - damage_extents.x1) * (damage_extents.y2 - damage_extents.y1)) * - (current_scale * current_scale); - + damage_sum_area(visible_damage) * (current_scale * current_scale); const int repaint_rescale_cost = (bbox.width * bbox.height) * (render_scale * render_scale); - if ((repaint_cost_current_scale > repaint_rescale_cost) || scale_nearly_1) + if ((repaint_cost_current_scale > repaint_rescale_cost) || rescale_magnification) { self->aux_buffer_current_scale[i][j] = render_scale; self->aux_buffers[i][j].subbuffer = wf::geometry_t{ @@ -333,29 +341,44 @@ class workspace_wall_t : public wf::signal::provider_t }; self->aux_buffer_damage[i][j] |= self->workspaces[i][j]->get_bounding_box(); - LOGI("Switch scale for ", i, "x", j, " from ", current_scale, " to ", render_scale); + return true; } + + return false; } void schedule_instructions( std::vector& instructions, const wf::render_target_t& target, wf::region_t& damage) override { - // Instructions for updating the contents of the workspaces + // Update workspaces in a render pass for (int i = 0; i < (int)self->workspaces.size(); i++) { for (int j = 0; j < (int)self->workspaces[i].size(); j++) { - consider_rescale_workspace_buffer(i, j); - for (auto& instance : instances[i][j]) + const auto ws_bbox = self->wall->get_workspace_rectangle({i, j}); + const auto visible_box = + geometry_intersection(self->wall->viewport, ws_bbox) - wf::origin(ws_bbox); + wf::region_t visible_damage = self->aux_buffer_damage[i][j] & visible_box; + if (consider_rescale_workspace_buffer(i, j, visible_damage)) + { + visible_damage |= visible_box; + } + + if (!visible_damage.empty()) { - instance->schedule_instructions(instructions, - self->aux_buffers[i][j], self->aux_buffer_damage[i][j]); - self->aux_buffer_damage[i][j].clear(); + scene::render_pass_params_t params; + params.instances = &instances[i][j]; + params.damage = std::move(visible_damage); + params.reference_output = self->wall->output; + params.target = self->aux_buffers[i][j]; + scene::run_render_pass(params, scene::RPASS_EMIT_SIGNALS); + self->aux_buffer_damage[i][j] ^= visible_damage; } } } + // Render the wall instructions.push_back(scene::render_instruction_t{ .instance = this, .target = target, @@ -365,6 +388,20 @@ class workspace_wall_t : public wf::signal::provider_t damage ^= self->get_bounding_box(); } + static gl_geometry scale_fbox( wf::geometry_t A, wf::geometry_t B, wf::geometry_t box) + { + const float px = 1.0 * (box.x - A.x) / A.width; + const float py = 1.0 * (box.y - A.y) / A.height; + const float px2 = 1.0 * (box.x + box.width - A.x) / A.width; + const float py2 = 1.0 * (box.y + box.height - A.y) / A.height; + return gl_geometry { + B.x + B.width * px, + B.y + B.height * py, + B.x + B.width * px2, + B.y + B.height * py2, + }; + } + void render(const wf::render_target_t& target, const wf::region_t& region) override { OpenGL::render_begin(target); @@ -379,34 +416,31 @@ class workspace_wall_t : public wf::signal::provider_t auto box = get_workspace_rect({i, j}); auto A = self->wall->viewport; auto B = self->get_bounding_box(); - box = scale_box(A, B, box); - + gl_geometry render_geometry = scale_fbox(A, B, box); auto& buffer = self->aux_buffers[i][j]; + + float dim = self->wall->get_color_for_workspace({i, j}); + const glm::vec4 color = glm::vec4(dim, dim, dim, 1.0); + if (!buffer.subbuffer.has_value()) { - OpenGL::render_transformed_texture( - {buffer.tex}, box, target.get_orthographic_projection()); - continue; + OpenGL::render_transformed_texture({buffer.tex}, + render_geometry, {}, target.get_orthographic_projection(), color); + } else + { + // The 0.999f come from trying to avoid floating-point artifacts + const gl_geometry tex_geometry = { + 0.0f, + 1.0f - 0.999f * buffer.subbuffer->height / buffer.viewport_height, + 0.999f * buffer.subbuffer->width / buffer.viewport_width, + 1.0f, + }; + + OpenGL::render_transformed_texture({buffer.tex}, + render_geometry, tex_geometry, + target.get_orthographic_projection(), + color, OpenGL::TEXTURE_USE_TEX_GEOMETRY); } - - const gl_geometry render_geometry = { - 1.0f * box.x, - 1.0f * box.y, - 1.0f * box.x + box.width, - 1.0f * box.y + box.height, - }; - - const gl_geometry tex_geometry = { - 0.0f, - 1.0f - 1.0f * buffer.subbuffer->height / buffer.viewport_height, - 1.0f * buffer.subbuffer->width / buffer.viewport_width, - 1.0f, - }; - - OpenGL::render_transformed_texture({buffer.tex}, - render_geometry, tex_geometry, - target.get_orthographic_projection(), - glm::vec4(1.0), OpenGL::TEXTURE_USE_TEX_GEOMETRY); } } } @@ -463,6 +497,19 @@ class workspace_wall_t : public wf::signal::provider_t } } + ~workspace_wall_node_t() + { + OpenGL::render_begin(); + for (auto& [_, buffers] : aux_buffers) + { + for (auto& [_, buffer] : buffers) + { + buffer.release(); + } + } + OpenGL::render_end(); + } + virtual void gen_render_instances( std::vector& instances, scene::damage_callback push_damage, wf::output_t *shown_on) override