【Wayland】Weston启动流程分析

article/2025/10/10 23:50:19

Weston启动流程分析

  • Weston是Wayland Compositor的实现。其Server端作为独立的进程运行在系统中。MakeFile中编译成果为,“weston”的可执行程序
  • MakeFile.am(weston 2.0.0)
bin_PROGRAMS += westonweston_LDFLAGS = -export-dynamic
weston_CPPFLAGS = $(AM_CPPFLAGS) -DIN_WESTON 		\-DMODULEDIR='"$(moduledir)"' \-DXSERVER_PATH='"@XSERVER_PATH@"'
weston_CFLAGS = $(AM_CFLAGS) $(COMPOSITOR_CFLAGS) $(LIBUNWIND_CFLAGS)
weston_LDADD = libshared.la libweston-@LIBWESTON_MAJOR@.la \$(COMPOSITOR_LIBS) $(LIBUNWIND_LIBS) \$(DLOPEN_LIBS) $(LIBINPUT_BACKEND_LIBS) \$(CLOCK_GETRES_LIBS) \-lmweston_SOURCES = 					\compositor/main.c				\compositor/weston-screenshooter.c		\compositor/text-backend.c			\compositor/xwayland.c

启动流程分析

  • 流程图:
    在这里插入图片描述

  • main函数:入口函数。其实现在 weston-2.0.0/compositor/main.c

  • 主要内容分析

int main(int argc, char *argv[])
{// Log日志初始化weston_log_set_handler(vlog, vlog_continue);weston_log_file_open(log);// 启动Logweston_log("%s\n"STAMP_SPACE "%s\n"STAMP_SPACE "Bug reports to: %s\n"STAMP_SPACE "Build: %s\n",PACKAGE_STRING, PACKAGE_URL, PACKAGE_BUGREPORT,BUILD_ID);// 创建全局唯一的Displaydisplay = wl_display_create();// 读取weston.ini文件中的配置if (load_configuration(&config, noconfig, config_file) < 0)goto out_signals;// 创建Compositorec = weston_compositor_create(display, &user_data);if (ec == NULL) {weston_log("fatal: failed to create compositor\n");goto out;}// 加载backend(默认为drm-backend)if (load_backend(ec, backend, &argc, argv, config) < 0) {weston_log("fatal: failed to create compositor backend\n");goto out;}// 捕获异常Signalcatch_signals();if (fd != -1) {// ...// 默认走 else if,创建socket} else if (weston_create_listening_socket(display, socket_name)) {goto out;}// 加载shellif (wet_load_shell(ec, shell, &argc, argv) < 0)goto out;// 唤醒compositorweston_compositor_wake(ec);// run:循环监听client端请求wl_display_run(display);}
  • 可以看出其大致的过程为:
  1. 初始化Log系统
  2. 创建Display(全局唯一)
  3. 加载配置文件(ini文件)
  4. 创建Compositor
  5. 加载backend
  6. 创建socket
  7. 加载shell
  8. 开启循环

初始化Log系统

  • weston-2.0.0/libweston/log.c
// 将vlog作为 log_handler
WL_EXPORT void
weston_log_set_handler(log_func_t log, log_func_t cont)
{log_handler = log;log_continue_handler = cont;
}// 使用log_handler进行输出,实际上使用的是main.c中传递过来的
// vlog
WL_EXPORT int
weston_vlog(const char *fmt, va_list ap)
{return log_handler(fmt, ap);
}// 代码中使用到的log输出接口
WL_EXPORT int
weston_log(const char *fmt, ...)
{int l;va_list argp;va_start(argp, fmt);l = weston_vlog(fmt, argp);va_end(argp);return l;
}
  • 实际上,log系统 使用vlog和vlog_continue这两个函数。两者的定义,在main.c中 。
static FILE *weston_logfile = NULL;
static void
weston_log_file_open(const char *filename)
{wl_log_set_handler_server(custom_handler);if (filename != NULL) {weston_logfile = fopen(filename, "a");if (weston_logfile)os_fd_set_cloexec(fileno(weston_logfile));}if (weston_logfile == NULL)weston_logfile = stderr;elsesetvbuf(weston_logfile, NULL, _IOLBF, 256);
}static int
vlog(const char *fmt, va_list ap)
{int l;l = weston_log_timestamp();l += vfprintf(weston_logfile, fmt, ap);return l;
}static int
vlog_continue(const char *fmt, va_list argp)
{return vfprintf(weston_logfile, fmt, argp);
}
  • 默认情况下weston_log_file_open函数,参数为NULL。所以log信息会输出到stderr中 。

创建Global Display

  • wl_display_create:wayland1.13.0/src/wayland-server.c
WL_EXPORT struct wl_display *
wl_display_create(void)
{struct wl_display *display;const char *debug;debug = getenv("WAYLAND_DEBUG");if (debug && (strstr(debug, "server") || strstr(debug, "1")))debug_server = 1;display = malloc(sizeof *display);if (display == NULL)return NULL;// 创建Loopdisplay->loop = wl_event_loop_create();if (display->loop == NULL) {free(display);return NULL;}// list初始化wl_list_init(&display->global_list);wl_list_init(&display->socket_list);wl_list_init(&display->client_list);wl_list_init(&display->registry_resource_list);wl_list_init(&display->protocol_loggers);// signal初始化wl_priv_signal_init(&display->destroy_signal);wl_priv_signal_init(&display->create_client_signal);display->id = 1;display->serial = 0;display->global_filter = NULL;display->global_filter_data = NULL;wl_array_init(&display->additional_shm_formats);return display;
}
  • wl_event_loop_create:wayland-1.13.0/src/event-loop.c
WL_EXPORT struct wl_event_loop *
wl_event_loop_create(void)
{struct wl_event_loop *loop;loop = malloc(sizeof *loop);if (loop == NULL)return NULL;// 最终调用epoll_createloop->epoll_fd = wl_os_epoll_create_cloexec();if (loop->epoll_fd < 0) {free(loop);return NULL;}wl_list_init(&loop->check_list);wl_list_init(&loop->idle_list);wl_list_init(&loop->destroy_list);wl_signal_init(&loop->destroy_signal);return loop;
}
  • 这部分主要就是初始化了Display结构体,使用epoll_create创建了loop。

加载配置文件

  • 配置文件:weston提供了配置文件,可以动态的改变运行配置(需要重启Server端进程),比如使用哪种shell、动画的类型、backend的类型等等。
  • compostior/main.c
static int
load_configuration(struct weston_config **config, int32_t noconfig,const char *config_file)
{// 默认的配置文件为 weston.iniconst char *file = "weston.ini";const char *full_path;*config = NULL;if (config_file)file = config_file;// 解析配置文件if (noconfig == 0)*config = weston_config_parse(file);if (*config) {full_path = weston_config_get_full_path(*config);weston_log("Using config file '%s'\n", full_path);setenv(WESTON_CONFIG_FILE_ENV_VAR, full_path, 1);return 0;}if (config_file && noconfig == 0) {weston_log("fatal: error opening or reading config file"" '%s'.\n", config_file);return -1;}weston_log("Starting with no config file.\n");setenv(WESTON_CONFIG_FILE_ENV_VAR, "", 1);return 0;
}
  • weston_config_parse函数负责具体解析配置文件。最终会解析成链表的数据结构。该函数代码行数较多,这里不再介绍。
  • 官方提供的weston.ini
[core]
#modules=cms-colord.so
#xwayland=true
#shell=desktop-shell.so
#gbm-format=xrgb2101010
#require-input=true[shell]
background-image=/usr/share/backgrounds/gnome/Aqua.jpg
background-color=0xff002244
background-type=tile
clock-format=minutes
panel-color=0x90ff0000
locking=true
animation=zoom
startup-animation=fade
#binding-modifier=ctrl
#num-workspaces=6
#cursor-theme=whiteglass
#cursor-size=24#lockscreen-icon=/usr/share/icons/gnome/256x256/actions/lock.png
#lockscreen=/usr/share/backgrounds/gnome/Garden.jpg
#homescreen=/usr/share/backgrounds/gnome/Blinds.jpg
#animation=fade[launcher]
icon=/usr/share/icons/gnome/24x24/apps/utilities-terminal.png
path=/usr/bin/gnome-terminal[launcher]
icon=/usr/share/icons/gnome/24x24/apps/utilities-terminal.png
path=@bindir@/weston-terminal[launcher]
icon=/usr/share/icons/hicolor/24x24/apps/google-chrome.png
path=/usr/bin/google-chrome[launcher]
icon=/usr/share/icons/gnome/24x24/apps/arts.png
path=@abs_top_builddir@/weston-flower[input-method]
path=@libexecdir@/weston-keyboard#[output]
#name=LVDS1
#mode=1680x1050
#transform=90
#icc_profile=/usr/share/color/icc/colord/Bluish.icc#[output]
#name=VGA1
#mode=173.00  1920 2048 2248 2576  1080 1083 1088 1120 -hsync +vsync
#transform=flipped#[output]
#name=X1
#mode=1024x768@60
#transform=flipped-90#[libinput]
#enable_tap=true#[touchpad]
#constant_accel_factor = 50
#min_accel_factor = 0.16
#max_accel_factor = 1.0[screen-share]
command=@bindir@/weston --backend=rdp-backend.so --shell=fullscreen-shell.so --no-clients-resize#[xwayland]
#path=@bindir@/Xwayland

创建Compositor

  • weston_compositor_create:libweston/compostior.c
WL_EXPORT struct weston_compositor *
weston_compositor_create(struct wl_display *display, void *user_data)
{struct weston_compositor *ec;struct wl_event_loop *loop;ec = zalloc(sizeof *ec);if (!ec)return NULL;// display为之前创建的全局displayec->wl_display = display;ec->user_data = user_data;// 初始化一系列signalwl_signal_init(&ec->destroy_signal);wl_signal_init(&ec->create_surface_signal);wl_signal_init(&ec->activate_signal);wl_signal_init(&ec->transform_signal);wl_signal_init(&ec->kill_signal);wl_signal_init(&ec->idle_signal);wl_signal_init(&ec->wake_signal);wl_signal_init(&ec->show_input_panel_signal);wl_signal_init(&ec->hide_input_panel_signal);wl_signal_init(&ec->update_input_panel_signal);wl_signal_init(&ec->seat_created_signal);wl_signal_init(&ec->output_pending_signal);wl_signal_init(&ec->output_created_signal);wl_signal_init(&ec->output_destroyed_signal);wl_signal_init(&ec->output_moved_signal);wl_signal_init(&ec->output_resized_signal);wl_signal_init(&ec->session_signal);ec->session_active = 1;ec->output_id_pool = 0;ec->repaint_msec = DEFAULT_REPAINT_WINDOW;ec->activate_serial = 1;// 这几步比较关键。再weston代码中可以看多很多这种调用。// wl_global_create有四个参数// display、interface、version、bind_func// 可以理解为:Display有一个全局对象List,这里为这个全局对象List中,加入一个新的全局对象。该对象的具体接口的实现,就是wl_compositor_interface。if (!wl_global_create(ec->wl_display, &wl_compositor_interface, 4,ec, compositor_bind))goto fail;// 同上wl_subcompositor_interface接口实现。if (!wl_global_create(ec->wl_display, &wl_subcompositor_interface, 1,ec, bind_subcompositor))goto fail;// 同上if (!wl_global_create(ec->wl_display, &wp_viewporter_interface, 1,ec, bind_viewporter))goto fail;// 同 上if (!wl_global_create(ec->wl_display, &wp_presentation_interface, 1,ec, bind_presentation))goto fail;// 创建了两个golbal对象,对应的interface为// 1. zwp_relative_pointer_manager_v1_interface// 2. zwp_pointer_constraints_v1_interfaceif (weston_input_init(ec) != 0)goto fail;// 初始化,几个关键的list: view\plane\layerwl_list_init(&ec->view_list);wl_list_init(&ec->plane_list);wl_list_init(&ec->layer_list);wl_list_init(&ec->seat_list);wl_list_init(&ec->pending_output_list);wl_list_init(&ec->output_list);wl_list_init(&ec->key_binding_list);wl_list_init(&ec->modifier_binding_list);wl_list_init(&ec->button_binding_list);wl_list_init(&ec->touch_binding_list);wl_list_init(&ec->axis_binding_list);wl_list_init(&ec->debug_binding_list);wl_list_init(&ec->plugin_api_list);// 初始化 首先的planeweston_plane_init(&ec->primary_plane, ec, 0, 0);weston_compositor_stack_plane(ec, &ec->primary_plane, NULL);wl_data_device_manager_init(ec->wl_display);wl_display_init_shm(ec->wl_display);loop = wl_display_get_event_loop(ec->wl_display);ec->idle_source = wl_event_loop_add_timer(loop, idle_handler, ec);// 初始化layerweston_layer_init(&ec->fade_layer, ec);weston_layer_init(&ec->cursor_layer, ec);weston_layer_set_position(&ec->fade_layer, WESTON_LAYER_POSITION_FADE);weston_layer_set_position(&ec->cursor_layer,WESTON_LAYER_POSITION_CURSOR);weston_compositor_add_debug_binding(ec, KEY_T,timeline_key_binding_handler, ec);return ec;fail:free(ec);return NULL;
}
  • 这里主要创建了几个全局对象,设置了这些全局对象对应的interface实现。并且初始化了view、layer、plane等一些关键的对象。

加载backend

  • load_backend:compositor/main.c
static int
load_backend(struct weston_compositor *compositor, const char *backend,int *argc, char **argv, struct weston_config *config)
{if (strstr(backend, "headless-backend.so"))return load_headless_backend(compositor, argc, argv, config);else if (strstr(backend, "rdp-backend.so"))return load_rdp_backend(compositor, argc, argv, config);else if (strstr(backend, "fbdev-backend.so"))return load_fbdev_backend(compositor, argc, argv, config);// 默认走 drm-backendelse if (strstr(backend, "drm-backend.so"))return load_drm_backend(compositor, argc, argv, config);else if (strstr(backend, "x11-backend.so"))return load_x11_backend(compositor, argc, argv, config);else if (strstr(backend, "wayland-backend.so"))return load_wayland_backend(compositor, argc, argv, config);weston_log("Error: unknown backend \"%s\"\n", backend);return -1;
}
  • load_drm_backend
static int
load_drm_backend(struct weston_compositor *c,int *argc, char **argv, struct weston_config *wc)
{struct weston_drm_backend_config config = {{ 0, }};struct weston_config_section *section;struct wet_compositor *wet = to_wet_compositor(c);// 走这里创建backendret = weston_compositor_load_backend(c, WESTON_BACKEND_DRM,&config.base);wet_set_pending_output_handler(c, drm_backend_output_configure);free(config.gbm_format);free(config.seat_id);return ret;
}
  • weston_compositor_load_backend:libweston/compositor.c
WL_EXPORT int
weston_compositor_load_backend(struct weston_compositor *compositor,enum weston_compositor_backend backend,struct weston_backend_config *config_base)
{int (*backend_init)(struct weston_compositor *c,struct weston_backend_config *config_base);if (backend >= ARRAY_LENGTH(backend_map))return -1;// 通过dlopen,打开drm-backend.so,查找 weston_backend_init 函数backend_init = weston_load_module(backend_map[backend], "weston_backend_init");if (!backend_init)return -1;// 执行weston_backend_init函数return backend_init(compositor, config_base);
}
  • weston_backend_init:libweston/compositor-drm.c
WL_EXPORT int
weston_backend_init(struct weston_compositor *compositor,struct weston_backend_config *config_base)
{struct drm_backend *b;struct weston_drm_backend_config config = {{ 0, }};if (config_base == NULL ||config_base->struct_version != WESTON_DRM_BACKEND_CONFIG_VERSION ||config_base->struct_size > sizeof(struct weston_drm_backend_config)) {weston_log("drm backend config structure is invalid\n");return -1;}config_init_to_defaults(&config);memcpy(&config, config_base, config_base->struct_size);// 创建 drm backendb = drm_backend_create(compositor, &config);if (b == NULL)return -1;return 0;
}
  • drm_backend_create:libweston/compositor-drm.c
static struct drm_backend *
drm_backend_create(struct weston_compositor *compositor,struct weston_drm_backend_config *config)
{// 使用libdrm接口,做一些初始化的动作// 创建output对象 drmModeGetConnector
}

创建Socket

  • Server进程创建监听socket
  • weston_create_listening_socket:compositor/main.c
static int
weston_create_listening_socket(struct wl_display *display, const char *socket_name)
{if (socket_name) {if (wl_display_add_socket(display, socket_name)) {weston_log("fatal: failed to add socket: %m\n");return -1;}} else {// 默认socketname为空。// 创建一个名为wayland-0的socketsocket_name = wl_display_add_socket_auto(display);if (!socket_name) {weston_log("fatal: failed to add socket: %m\n");return -1;}}setenv("WAYLAND_DISPLAY", socket_name, 1);return 0;
}

加载shell

  • wet_load_shell:compositor/main.c
static int
wet_load_shell(struct weston_compositor *compositor,const char *name, int *argc, char *argv[])
{int (*shell_init)(struct weston_compositor *ec,int *argc, char *argv[]);// 默认:// 使用dlopen,打开desktop-shell.so,查找wet_shell_init函数shell_init = wet_load_module_entrypoint(name, "wet_shell_init");if (!shell_init)return -1;// 调用wet_shell_initif (shell_init(compositor, argc, argv) < 0)return -1;return 0;
}
  • wet_shell_init:deskstop-shell/shell.c
WL_EXPORT int
wet_shell_init(struct weston_compositor *ec,int *argc, char *argv[])
{// 创建desktopshell->desktop = weston_desktop_create(ec, &shell_desktop_api, shell);if (!shell->desktop)return -1;// 创建全局对象if (wl_global_create(ec->wl_display,&weston_desktop_shell_interface, 1,shell, bind_desktop_shell) == NULL)return -1;}

开启循环

  • 这里的循环,指使用epoll机制,监听对socket(上面Server端创建的socket)产生的读写事件。
WL_EXPORT void
wl_display_run(struct wl_display *display)
{display->run = 1;while (display->run) {wl_display_flush_clients(display);wl_event_loop_dispatch(display->loop, -1);}
}
  • wl_event_loop_dispatch:event-loop.c
WL_EXPORT int
wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout)
{struct epoll_event ep[32];struct wl_event_source *source;int i, count, n;wl_event_loop_dispatch_idle(loop);count = epoll_wait(loop->epoll_fd, ep, ARRAY_LENGTH(ep), timeout);if (count < 0)return -1;for (i = 0; i < count; i++) {source = ep[i].data.ptr;if (source->fd != -1)source->interface->dispatch(source, &ep[i]);}wl_event_loop_process_destroy_list(loop);wl_event_loop_dispatch_idle(loop);do {n = post_dispatch_check(loop);} while (n > 0);return 0;
}

http://chatgpt.dhexx.cn/article/7yreGhEL.shtml

相关文章

Weston 纹理倒置(render-gl)

纹理倒置 背景 在 render-gl 接入 frame buffer object 实现 off-screen 渲染后,发现得到的渲染图发生了180的倒置. 查阅了有关资料后,在 eglspec.1.5 中的 2.2.2.1 Native Surface Coordinate Systems 找到了答案: The coordinate system for native windows and pixmaps …

【Wayland】Wayland简介与定制指导

Wayland与Weston简介 由于某些原因。移植并定制一套基于Wayland的Compositor。Wayland与Weston&#xff0c;是两个相辅相成的概念。这里简单总结一下&#xff1a; wayland是一套为“显示”服务的协议&#xff0c;基于C/S结构。它定制了一套标准的接口、基本通信方式。wayland…

display:weston:weston-simple-egl

写在前面&#xff1a; 客户端渲染 在Wayland架构中&#xff0c;客户端UI的所有呈现均由客户端代码执行&#xff0c;通常由客户端使用的图形工具包执行。 图形工具箱可以使用其希望呈现UI元素的任何方法&#xff1a;在CPU上进行软件呈现&#xff0c;使用GLES进行硬件呈现。 W…

Ubuntu 20.04 X86成功编译运行wayland、wayland-protocols、weston,亲测有效,踩了很多坑,完美解决。

编译前期准备&#xff1a; 1、更换国内源&#xff1a; #添加阿里源 deb http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse deb-src http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse deb http://mirrors.aliyun.c…

weston 窗口管理 (1)

窗口管理 (1) 一、概述 在传统嵌入式场景下,通常只会运行一个UI程序,故相当于单窗口程序,无需桌面服务器的介入;在桌面系统下,对于每一个UI程序而言,它们的行为相比于嵌入式场景仍然没有发生改变,其对接的仍然是窗口,只不过在同一个时刻允许多个UI程序同时运行. 无论如何对于…

weston 简介

参考???weston wiki Weston - Gentoo Wiki weston (1): Linux man pages – code.tools Weston-1.12.0 非常详尽&#xff0c;多图慎入&#xff1a;Wayland与Weston简介 - 云社区 - 腾讯云 什么是weston&#xff1f; Wayland是一套display server(Wayland compositor)与…

waylandweston

简单地说&#xff0c;Wayland是一套display server(Wayland compositor)与client间的通信协议&#xff0c;而Weston是Wayland compositor的参考实现。其官网为http://wayland.freedesktop.org/。它们定位于在Linux上替换X图形系统。X图形系统经历了30年左右的发展&#xff0c;其…

weston 1: 编译与运行傻瓜教程

本人Kubuntu版本是22.04 sudo apt-get update sudo apt-get upgrade 进入主目录 cd $HOME/ mkdir install mkdir works vim ~/.bashrc export WLD$HOME/install source ~/.bashrc cd works wayland git clone https://gitlab.freedesktop.org/wayland/wayland.git cd …

weston input 概述

weston input 概述 零、前言 本文描述了有关于 weston (基于 wayland 协议一种显示服务器的实现) 中有关于输入设备管理的部分;为了聚焦于此,本文不会对 weston 整体或 wayland 协议进行过多的阐述. 考虑到读者可能存在不同的需求,采用分层次的描述方式,主要面向以下两类人群…

weston 2: 登录后直接启动weston配置

本人Kubuntu版本是22.04 名词&#xff1a;SDDM&#xff08;SDDM - Arch Linux 中文维基&#xff09;显示管理器 配置流程如下&#xff1a; 1.修改配置文件 a.配置.bashrc vim ~/.bashrc //以下内容删除 #export WLD$HOME/install #export LD_LIBRARY_PATH$WLD/lib/x86_64-…

Weston介绍

Weston结构说明 Weston源码结构 clients&#xff1a;wayland显示客户端应用 compositor&#xff1a;合成器进程&#xff08;服务端&#xff09;&#xff0c;窗体风 格样式处理 libweston&#xff1a;合成器以及客户端渲染处理以及驱动实现方式&#xff0c;以及wayland服务与客户…

Wayland/Weston 启动方式简介

前言 本文简单介绍 Weston 常用的几种 backend 启动方式。目前最新的 Weston 8.0.0 支持如下几种 backend&#xff1a; drm-backendfbdev-backendheadless-backendrdp-backendwayland-backendx11-backend 其中 headless-backend 不带任何 UI 界面&#xff0c;主要用于 westo…

weston设置

weston设置 屏幕旋转180度方法修改标题栏位置启动配置文件 屏幕旋转180度方法 编辑 /etc/xdg/weston/weston.ini文件&#xff0c;增加如下语句 [output] nameDSI-1 transform180其中name为你的显示屏名称&#xff0c;可以通过如下命令来查看显示屏名称&#xff1a; card0-DS…

Weston 窗口管理(2)

窗口管理(2) 本文基于 weston 分支 10.0.2 进行描述. 五、概述 本文为窗口管理(1)的续章,更多站在开发者角度,以 weston 的代码实现讲解窗口管理(1)中所实现的部分业务场景. 六、数据结构 在窗口管理(1)中曾经描述过 weston 具体的分层逻辑,如下: 再进一步可以把 WESTON_LAY…

01-weston 简介

参考​​​​​​weston wiki Weston - Gentoo Wiki weston (1): Linux man pages – code.tools Weston-1.12.0 非常详尽&#xff0c;多图慎入&#xff1a;Wayland与Weston简介 - 云社区 - 腾讯云 什么是weston&#xff1f; Wayland是一套display server(Wayland compos…

disunity的使用

1. 下载并安装好jdk: 下载地址&#xff1a;http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 安装教程&#xff1a;http://jingyan.baidu.com/article/6dad5075d1dc40a123e36ea3.html 2.下载disunity: https://…

T-digest

目录 算法算法原理空间消耗及错误界限 示例T-digest的建立T-digest的查询 相关链接 上一篇博客中讲述了使用 R a n d o m Random Random算法进行 q u a n t i l e quantile quantile估算&#xff0c;详情可见Random&#xff0c;本博客将讲诉另外一个 q u a n t i l e quantile …

[反编译U3D]Decompile Unity Resources 修正

反编译unity project的资源文件&#xff0c;包括ios&#xff0c;android&#xff0c;pc等&#xff0c;仅供学习使用&#xff01; 1.disunity Examples 1.1disunityGUI 1.1.2DiunityGUI 使用方法 2.unity3d decompiler 3.UnityAssetsExplorer 反编译unity project的资源文件&…

edit distance 理解

一直没有理解到inert i delete j 的意思。看看图就可以明白了。 对于那道面试题&#xff1a;http://www.careercup.com/question?id6287528252407808 k-palindrome. 最精妙的地方在于只考虑 k 长度以内的改变&#xff0c;这样就可以判断出来了。速度是O(k*n) 1. Definition o…