#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cube-control-signal.hpp" class render_test_t : public wf::plugin_interface_t { wf::shared_data::ref_ptr_t repo; std::shared_ptr rectangle; std::map> solids; int passes = 0; wf::signal::connection_t count_passes = [this] (auto) { ++passes; }; public: void init() override { wf::get_core().connect(&count_passes); repo->register_method("test/partial", [] (wf::json_t data) { auto output = wf::get_core().output_layout->find_output(std::string(data["output"])); auto g = output->get_layout_geometry(); int w = output->handle->width, h = output->handle->height; wf::auxilliary_buffer_t buffer; buffer.allocate({w, h}); wf::render_target_t target{buffer}; target.geometry = g; target.scale = output->handle->scale; target.wl_transform = output->handle->transform; wf::render_pass_params_t params; params.target = target; params.damage = g; params.background_color = {1, 0, 1, 1}; params.flags = wf::RPASS_CLEAR_BACKGROUND | wf::RPASS_NO_PRESENTATION; wf::render_pass_t::run(params); unsigned depth; wf::gles::run_in_context([&] { wf::gles::bind_render_buffer(target); glGenRenderbuffers(1, &depth); glBindRenderbuffer(GL_RENDERBUFFER, depth); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, w, h); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth); }); std::vector instances; wf::get_core().scene()->gen_render_instances(instances, [] (auto&) {}, output); params.instances = &instances; params.damage = wf::geometry_t{g.x + 10, g.y + 10, 20, 20}; auto allowed = target.framebuffer_region_from_geometry_region(params.damage); params.background_color = {0, 0, 0, 1}; wf::render_pass_t::run(params); wf::gles::run_in_context([&] { wf::gles::bind_render_buffer(target); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0); glDeleteRenderbuffers(1, &depth); }); std::vector pixels(w * h); wlr_texture_read_pixels_options opts{}; opts.data = pixels.data(); opts.format = DRM_FORMAT_ABGR8888; opts.stride = w * 4; wlr_texture_read_pixels(buffer.get_texture(), &opts); int outside = 0, inside = 0; for (int y = 0; y < h; ++y) for (int x = 0; x < w; ++x) if ((pixels[y * w + x] & 0x00ffffff) != 0x00ff00ff) { if (pixman_region32_contains_point(allowed.to_pixman(), x, y, nullptr)) ++inside; else ++outside; } wf::json_t result; result["outside"] = outside; result["inside"] = inside; return result; }); repo->register_method("test/held", [] (wf::json_t data) { auto output = wf::get_core().output_layout->find_output(std::string(data["output"])); wayfire_toplevel_view view; for (auto candidate : wf::get_core().get_all_views()) if (candidate->get_output() == output && toplevel_cast(candidate)) view = toplevel_cast(candidate); cube_workspace_animation_signal signal{{1, 0}, output->wset()->get_current_workspace(), view}; output->emit(&signal); wf::json_t result; result["found"] = bool(view); result["carried-out"] = signal.carried_out; return result; }); repo->register_method("test/stats", [this] (wf::json_t) { wf::json_t result; result["passes"] = passes; passes = 0; return result; }); repo->register_method("test/solid", [this] (wf::json_t data) { std::string key = data["key"]; auto& solid = solids[key]; if (data.has_member("close") && bool(data["close"])) { if (solid) { solid->damage(); wf::scene::set_node_enabled(solid->get_root_node(), false); solid->close(); solid.reset(); } return wf::json_t{}; } auto output = wf::get_core().output_layout->find_output(std::string(data["output"])); if (!solid) solid = wf::color_rect_view_t::create(wf::VIEW_ROLE_DESKTOP_ENVIRONMENT, output, (wf::scene::layer)(int)data["layer"]); solid->set_color({double(data["r"]), double(data["g"]), double(data["b"]), double(data["a"])}); solid->set_geometry({double(data["x"]), double(data["y"]), double(data["w"]), double(data["h"])}); solid->set_border(0); return wf::json_t{}; }); repo->register_method("test/workspace-panel", [] (wf::json_t data) { auto output = wf::get_core().output_layout->find_output(std::string(data["output"])); auto g = output->get_relative_geometry(); wf::auxilliary_buffer_t buffer; buffer.allocate(wf::dimensions(g)); wf::render_target_t target{buffer}; target.geometry = g; auto node = std::make_shared(output, wf::point_t{int(data["x"]), int(data["y"])}); node->include_desktop_environment = false; node->background = wf::color_t{0, 0, 0, 0}; std::vector instances; node->gen_render_instances(instances, [] (auto&) {}, output); wf::render_pass_params_t params; params.target = target; params.damage = g; params.instances = &instances; params.background_color = {0, 0, 0, 0}; params.flags = wf::RPASS_CLEAR_BACKGROUND | wf::RPASS_NO_PRESENTATION; wf::render_pass_t::run(params); int w = g.width, h = g.height; std::vector pixels(w * h); wlr_texture_read_pixels_options opts{}; opts.data = pixels.data(); opts.format = DRM_FORMAT_ABGR8888; opts.stride = w * 4; wlr_texture_read_pixels(buffer.get_texture(), &opts); int cyan = 0; for (auto p : pixels) if ((p & 0x00ffffff) == 0x00ffff00) ++cyan; wf::json_t result; result["cyan"] = cyan; return result; }); repo->register_method("test/snapshot", [] (wf::json_t) { auto output = wf::get_core().output_layout->get_outputs().front(); wf::auxilliary_buffer_t buffer; auto g = output->get_layout_geometry(); int w = output->handle->width, h = output->handle->height; buffer.allocate({w, h}); wf::render_target_t target{buffer}; target.geometry = g; target.scale = output->handle->scale; target.wl_transform = output->handle->transform; output->render->render_desktop(target); std::vector pixels(w * h); wlr_texture_read_pixels_options opts{}; opts.data = pixels.data(); opts.format = DRM_FORMAT_ABGR8888; opts.stride = w * 4; wlr_texture_read_pixels(buffer.get_texture(), &opts); std::ofstream f(std::string(getenv("XDG_RUNTIME_DIR")) + "/snapshot.ppm", std::ios::binary); f << "P6\n" << w << " " << h << "\n255\n"; for (auto p : pixels) { f.put(p & 255); f.put((p >> 8) & 255); f.put((p >> 16) & 255); } return wf::json_t{}; }); repo->register_method("test/rectangle", [this] (wf::json_t data) { if (bool(data["show"])) { auto output = wf::get_core().output_layout->get_outputs().front(); if (!rectangle) rectangle = wf::color_rect_view_t::create(wf::VIEW_ROLE_TOPLEVEL, output, wf::scene::layer::WORKSPACE); rectangle->set_color(data.has_member("blue") && bool(data["blue"]) ? wf::color_t{0.0, 0.0, 1.0, 1.0} : wf::color_t{0.0, 1.0, 0.0, 1.0}); rectangle->set_geometry(data.has_member("moved") && bool(data["moved"]) ? wf::geometry_t{150, 120, 150, 120} : wf::geometry_t{50, 50, 400, 300}); } else if (rectangle) { // color_rect_view_t::close() only emits the unmap signal; // emulate a real surface unmap's damage and scene removal. rectangle->damage(); wf::scene::set_node_enabled(rectangle->get_root_node(), false); rectangle->close(); rectangle.reset(); } return wf::json_t{}; }); repo->register_method("test/cube", [] (wf::json_t data) { wf::json_t result; auto output = data.has_member("output") ? wf::get_core().output_layout->find_output(std::string(data["output"])) : wf::get_core().output_layout->get_outputs().front(); double angle = data.has_member("angle") ? double(data["angle"]) : 0.65; cube_control_signal signal{angle, 0.8, 0.0, data.has_member("stop") && bool(data["stop"]), false}; output->emit(&signal); result["active"] = output->is_plugin_active("cube"); result["carried-out"] = signal.carried_out; return result; }); repo->register_method("test/inhibit", [] (wf::json_t data) { for (auto output : wf::get_core().output_layout->get_outputs()) output->set_inhibited(bool(data["inhibit"])); return wf::json_t{}; }); } void fini() override { for (auto& [key, solid] : solids) if (solid) solid->close(); repo->unregister_method("test/solid"); repo->unregister_method("test/stats"); repo->unregister_method("test/held"); repo->unregister_method("test/partial"); if (rectangle) { rectangle->close(); rectangle.reset(); } repo->unregister_method("test/rectangle"); repo->unregister_method("test/snapshot"); repo->unregister_method("test/workspace-panel"); repo->unregister_method("test/cube"); repo->unregister_method("test/inhibit"); } }; DECLARE_WAYFIRE_PLUGIN(render_test_t);