#include "xdg-shell-client-protocol.hpp" #include "xdg-decoration-unstable-v1-client-protocol.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct App { wayland::display_t display; wayland::registry_t registry; wayland::compositor_t compositor; wayland::xdg_wm_base_t xdg_wm; wayland::zxdg_decoration_manager_v1_t dec_mgr; wayland::surface_t wl_surface; wayland::xdg_surface_t xdg_surface; wayland::xdg_toplevel_t xdg_toplevel; EGLDisplay edpy = EGL_NO_DISPLAY; EGLConfig ecfg = nullptr; EGLContext ectx = EGL_NO_CONTEXT; EGLSurface esurf = EGL_NO_SURFACE; wl_egl_window *wegl = nullptr; sk_sp gl_iface; sk_sp gr_ctx; sk_sp sk_surface; int win_w = 800, win_h = 600; bool running = true; void init_wayland() { registry = display.get_registry(); registry.on_global() = [&](uint32_t name, const std::string &iface, uint32_t ver) { if (iface == wayland::compositor_t::interface_name) compositor = registry.bind( name, std::min(ver, 4)); else if (iface == wayland::xdg_wm_base_t::interface_name) xdg_wm = registry.bind(name, 1); else if (iface == wayland::zxdg_decoration_manager_v1_t::interface_name) dec_mgr = registry.bind(name, 1); }; xdg_wm.on_ping() = [&](uint32_t serial) { xdg_wm.pong(serial); }; display.roundtrip(); if (!compositor || !xdg_wm) { fprintf(stderr, "missing compositor\n"); exit(1); } wl_surface = compositor.create_surface(); xdg_surface = xdg_wm.get_xdg_surface(wl_surface); xdg_toplevel = xdg_surface.get_toplevel(); if (dec_mgr) { auto deco = dec_mgr.get_toplevel_decoration(xdg_toplevel); deco.set_mode(wayland::zxdg_toplevel_decoration_v1_mode::client_side); } xdg_toplevel.set_title("Skia Hello World"); xdg_toplevel.on_close() = [&] { running = false; }; xdg_surface.on_configure() = [&](uint32_t serial) { xdg_surface.ack_configure(serial); wl_surface.commit(); }; xdg_toplevel.on_configure() = [&](int32_t w, int32_t h, std::vector) { if (w > 0 && h > 0 && (w != win_w || h != win_h)) { win_w = w; win_h = h; if (wegl) { wl_egl_window_resize(wegl, win_w, win_h, 0, 0); recreate_skia_surface(); } } }; wl_surface.commit(); display.roundtrip(); } void init_egl() { edpy = eglGetDisplay((EGLNativeDisplayType)display.c_ptr()); eglInitialize(edpy, nullptr, nullptr); const EGLint cfgAttribs[] = {EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_NONE}; EGLint n = 0; eglChooseConfig(edpy, cfgAttribs, &ecfg, 1, &n); const EGLint ctxAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; ectx = eglCreateContext(edpy, ecfg, EGL_NO_CONTEXT, ctxAttribs); wegl = wl_egl_window_create(wl_surface, win_w, win_h); esurf = eglCreateWindowSurface(edpy, ecfg, (EGLNativeWindowType)wegl, nullptr); eglMakeCurrent(edpy, esurf, esurf, ectx); eglSwapInterval(edpy, 1); } void init_skia() { gl_iface = GrGLMakeNativeInterface(); gr_ctx = GrDirectContext::MakeGL(gl_iface); recreate_skia_surface(); } void recreate_skia_surface() { GrGLFramebufferInfo fbInfo{0, GL_RGBA8}; GrBackendRenderTarget backendRT(win_w, win_h, 0, 8, fbInfo); SkSurfaceProps props(0, kUnknown_SkPixelGeometry); sk_surface = SkSurfaces::WrapBackendRenderTarget( gr_ctx.get(), backendRT, kBottomLeft_GrSurfaceOrigin, kRGBA_8888_SkColorType, nullptr, &props); } void draw_frame() { SkCanvas *c = sk_surface->getCanvas(); c->clear(SkColorSetARGB(255, 20, 22, 26)); SkPaint paint; paint.setAntiAlias(true); paint.setColor(SkColorSetARGB(255, 240, 240, 255)); SkFont font; font.setSize(48); const char *text = "Hello, world!"; SkRect bounds; font.measureText(text, strlen(text), SkTextEncoding::kUTF8, &bounds); float x = (win_w - bounds.width()) / 2 - bounds.left(); float y = (win_h + bounds.height()) / 2 - bounds.bottom(); c->drawSimpleText(text, strlen(text), SkTextEncoding::kUTF8, x, y, font, paint); sk_surface->flushAndSubmit(); eglSwapBuffers(edpy, esurf); } void run() { while (running) { display.dispatch_pending(); display.flush(); draw_frame(); std::this_thread::sleep_for(std::chrono::milliseconds(16)); } } void cleanup() { gr_ctx->flushAndSubmit(); gr_ctx->releaseResourcesAndAbandonContext(); sk_surface.reset(); gl_iface.reset(); eglMakeCurrent(edpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroySurface(edpy, esurf); wl_egl_window_destroy(wegl); eglDestroyContext(edpy, ectx); eglTerminate(edpy); } }; int main() { App a; a.init_wayland(); a.init_egl(); a.init_skia(); a.run(); a.cleanup(); return 0; }