dotnet X11 调用 XRootWindow 是否耗时

news/2024/10/5 12:24:59/文章来源:https://www.cnblogs.com/lindexi/p/18274612

本文将通过阅读 lib x11 代码告诉大家,调用 XRootWindow 函数是不耗时的,没有成本的

在我阅读 Avalonia 和 CPF 和 UNO 框架的代码的时候,我发现了很多时候都是在需要用到 RootWindow 时,调用 XRootWindow 或 XDefaultRootWindow 获取 RootWindow 的值。此时我想着是否将 RootWindow 存放起来,这样可以稍微提升一点性能

在对某个函数调用进行性能测量考虑时,不仅可以使用基准性能测试工具进行测试,还可以通过阅读代码的方式了解实现原理从而了解其性能

通过阅读 lib x11 的代码,我发现了 XRootWindow 方法只是从结构体里面将值取出来,性能损耗其实和自己将 RootWindow 存起来可以认为是等价的

在 Macros.c 文件的对 XRootWindow 方法的定义代码如下

Window XRootWindow (Display *dpy, int scr)
{return (RootWindow(dpy,scr));
}

以上代码的 RootWindow 是一个宏定义,定义在 Xlib.h 文件中,代码如下

#define RootWindow(dpy, scr) 	(ScreenOfDisplay(dpy,scr)->root)

从以上的代码可以看到,实现就是将传入的 Display 和 screen number 传入到 ScreenOfDisplay 里面。最后取出来一个 root 字段

再继续看看 ScreenOfDisplay 这个宏的定义,代码如下

#define ScreenOfDisplay(dpy, scr)(&((_XPrivDisplay)(dpy))->screens[scr])

可以看到实现的逻辑十分简单,那就是将传入的 Display 转换为 _XPrivDisplay 结构体类型。接着获取其 screens 字段,这个字段是一个数组,或者准确说是一个指向 Screen 数组类型的指针。再取其第 scr 项,也就是取传入的 screen number 项

回到咱 C# 代码,如以下的代码定义

var display = XOpenDisplay(IntPtr.Zero);
var screen = XDefaultScreen(display);

以上代码拿到的 display 就是以上的 Display 的值,也就是实际的 _XPrivDisplay 结构体类型指针。以上的 screen 准确来说是 screen number 的意思,大部分情况下返回 0 的值

在咱 C# 代码调用 XRootWindow 方法时,如以下代码,其实等同于在 display 里面先取 Screen 再取其 root 字段

var xRootWindow = XRootWindow(display, screen);

那这么说是否可以绕过 XRootWindow 方法,直接不安全使用 _XPrivDisplay 结构体类型指针获取 RootWindow 内容?答案是可以的

开始之前必须说明的是,这样的方式是不安全的,强依赖 xlib 的实现。好在这部分逻辑好久都没有变更了,大概在你的设备上,我以下的代码也能跑起来

先阅读 _XPrivDisplay 结构体,大概代码如下

typedef struct#ifdef XLIB_ILLEGAL_ACCESS_XDisplay#endif{XExtData *ext_data;	/* hook for extension to hang data * /struct _XPrivate *private1;int fd;			/* Network socket. * /int private2;int proto_major_version;/* major version of server's X protocol * /int proto_minor_version;/* minor version of servers X protocol * /char *vendor;		/* vendor of the server hardware * /XID private3;XID private4;XID private5;int private6;XID (*resource_alloc)(	/* allocator function * /struct _XDisplay*);int byte_order;		/* screen byte order, LSBFirst, MSBFirst * /int bitmap_unit;	/* padding and data requirements * /int bitmap_pad;		/* padding requirements on bitmaps * /int bitmap_bit_order;	/* LeastSignificant or MostSignificant * /int nformats;		/* number of pixmap formats in list * /ScreenFormat *pixmap_format;	/* pixmap format list * /int private8;int release;		/* release of the server * /struct _XPrivate *private9, *private10;int qlen;		/* Length of input event queue * /unsigned long last_request_read; /* seq number of last event read * /unsigned long request;	/* sequence number of last request. * /XPointer private11;XPointer private12;XPointer private13;XPointer private14;unsigned max_request_size; /* maximum number 32 bit words in request* /struct _XrmHashBucketRec *db;int (*private15)(struct _XDisplay*);char *display_name;	/* "host:display" string used on this connect* /int default_screen;	/* default screen for operations * /int nscreens;		/* number of screens on this server* /Screen *screens;	/* pointer to list of screens * /unsigned long motion_buffer;	/* size of motion buffer * /unsigned long private16;int min_keycode;	/* minimum defined keycode * /int max_keycode;	/* maximum defined keycode * /XPointer private17;XPointer private18;int private19;char *xdefaults;	/* contents of defaults from server * //* there is more to this structure, but it is private to Xlib * /}#ifdef XLIB_ILLEGAL_ACCESSDisplay,#endif*_XPrivDisplay;

如上文,咱核心需要的就是拿到 Screen *screens; /* pointer to list of screens * / 字段的内容

继续先看看 Screen 的定义,代码如下

typedef struct {XExtData *ext_data;	/* hook for extension to hang data * /struct _XDisplay *display;/* back pointer to display structure * /Window root;		/* Root window id. * /int width, height;	/* width and height of screen * /int mwidth, mheight;	/* width and height of  in millimeters * /int ndepths;		/* number of depths possible * /Depth *depths;		/* list of allowable depths on the screen * /int root_depth;		/* bits per pixel * /Visual *root_visual;	/* root visual * /GC default_gc;		/* GC for the root root visual * /Colormap cmap;		/* default color map * /unsigned long white_pixel;unsigned long black_pixel;	/* White and Black pixel values * /int max_maps, min_maps;	/* max and min color maps * /int backing_store;	/* Never, WhenMapped, Always * /Bool save_unders;long root_input_mask;	/* initial root input mask * /} Screen;

由于咱只想从 _XPrivDisplay 拿到 screens 字段,于是在 C# 代码定义里面,可以使用 StructLayout 加 Explicit 方式跳过结构体定义,只定义核心的字段

[StructLayout(LayoutKind.Explicit)]
struct Display
{[FieldOffset(228)]public int nscreens;[FieldOffset(232)]public IntPtr Screens;
}

以上代码的 [FieldOffset(228)] 是根据上文的 _XPrivDisplay 算到的在 nscreens 字段在整个结构体里面的 byte 量,换句话说就是在第几个 byte 就是 nscreens 字段

同样对 Screen 结构体做相同的定义,只定义其中我需要用到的属性

[StructLayout(LayoutKind.Explicit)]
struct Screen
{[FieldOffset(8)]public IntPtr _XDisplay;[FieldOffset(8 + 8)]public int RootWindow;[FieldOffset(8 + 8 + 8)]public int Width;[FieldOffset(8 + 8 + 8 + 4)]public int Height;
}

尝试通过自己定义的结构体和 XRootWindow 获取 RootWindow 的值,看是否相同,代码如下

var display = XOpenDisplay(IntPtr.Zero);
var screen = XDefaultScreen(display);var xRootWindow = XRootWindow(display, screen);unsafe
{var pDisplay = (Display*)display;var firstScreen = pDisplay->Screens;Screen* pScreen = (Screen*) firstScreen;var rootWindowFromPScreen = pScreen->RootWindow;Console.WriteLine($"{rootWindowFromPScreen} xRootWindow={xRootWindow}");
}

尝试运行以上代码,可以在控制台里输出以下内容

1729 xRootWindow=1729

可以看到两个值是相同的,证明咱这个获取方式是正确的,也证明了 xlib 实现确实如此

如此也可以证明 XRootWindow 方法获取是不耗时没成本的,只是从结构体将值取出而已。不需要自己存着,自己存着和调用方法拿从业务角度没有性能上的差异

那 XDefaultRootWindow 呢?通过阅读 Macros.c 代码,可以发现和 XRootWindow 差不多,代码定义如下

Window XRootWindow (Display *dpy, int scr)
{return (RootWindow(dpy,scr));
}Window XDefaultRootWindow (Display *dpy)
{return (RootWindow(dpy,DefaultScreen(dpy)));
}

可以看到不同点仅仅只是 XDefaultRootWindow 传入 RootWindow 的 scr 是从 DefaultScreen 拿的

继续进入 Macros.c 代码,可以看到 DefaultScreen 宏的定义如下

#define DefaultScreen(dpy) 	(((_XPrivDisplay)(dpy))->default_screen)

如以上代码可以看到 XDefaultScreen 也只是从 _XPrivDisplay 结构体取出 default_screen 字段而已,也可以忽略

如此即可了解到调用 XRootWindow 和 XDefaultRootWindow 都只是从 Display 结构体取出字段而已,可以在业务端随意调用,没有成本

本文以上代码放在 github 和 gitee 上,可以使用如下命令行拉取代码

先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码

git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 7ad18fcc3b99003e0864e54e1ea6e696909b4b3b

以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码,将 gitee 源换成 github 源进行拉取代码

git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin 7ad18fcc3b99003e0864e54e1ea6e696909b4b3b

获取代码之后,进入 X11/LabajaycolibearLuleacearewearjaykee 文件夹,即可获取到源代码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/733440.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++

C++中的isalnum可以判断一个字符是否为字母或者十进制数; 需包含头文件cctype 函数原型:int isalnum(int_C); 通过实验可知,int_C可以为字符、数字; 并且返回值为int类型,判断为true则返回1,判断为false则返回0; 接下来介绍sizeof(string) string s; sizeof(s) …

记vscode无法启动解决办法

背景之前都好好的,突然就不行了,点击快捷方式或直接程序右击管理员运行均没有任何反应。处理方式(确认使用此解决办法可以看下方红字部分,是否也有类似提示):创建null服务。(启发站点:shellvon的回复):https://github.com/microsoft/vscode/issues/185298 步骤 1、要…

OOP第7-8次作业总结

前言: 时光飞快, 转眼就到了学期末尾。从第七次作业开始,作业便开始加难度了。第七次作业加了互斥开关和窗帘,但是这次的电子元件不能像之前简单的写如同写商品类这样简单的写出,需要思考如何设计这个电器类。并且,在加上上面两个类的基础上,电路开放了串联电路中有串联…

[C++ Primer] 泛型算法

记录了C++标准库提供的泛型算法相关重难点。泛型算法 初识泛型大多数算法定义在头文件algorithm中。标准库还在头文件numeric中定义了一组数值范型算法。那些只接受一个单一迭代器来表示第二个序列的算法,都假定第二个序列至少与第一个序列一样长。 // v2中的元素数目应该至少…

prometheus指标终端绘图工具

最近搞了一个prometheus 指标终端展示工具,有兴趣的可以试试:本文来自博客园,作者:charlieroro,转载请注明原文链接:https://www.cnblogs.com/charlieroro/p/18274557

CC4+CC5分析利用

CC4+CC5分析利用 CC4分析与利用 学了前面的cc2,其实cc4就是将cc2使用的InvokerTransformer替换成InstantiateTransformer来加载字节码(CC3里面有说)。 把最后调用的transform方法改为:Transformer[] transformers = new Transformer[]{new ConstantTransformer(TrAXFilter.…

DApp设计与开发 课程笔记(三):erc20 | erc721

笔记对应课程内容为成都信息工程大学区块链产业学院老师梁培利的DApp 设计与开发 07-09 课 笔记中提到的名词不做过多解释 不懂就搜!ERC-20区块链专业的学生需要熟知erc20的接口,不看代码的前提下能够独立完成,至少你要知道有哪些属性和函数接口。balanceof, address, balan…

大白话讲解会计科目

大白话讲解会计科目

15款主流项目进度软件对比

15好用的款主流项目进度管理软件:PingCode、Worktile、Trello、Tower、Asana、Smartsheet、Teambition、ClickUp、Wrike、Monday.com、Notion、禅道、飞书、云效、蓝凌。严格的进度管理有助于更好地控制项目进展,提升团队效率,最终实现项目成功。一个好的项目进度管理工具可…

《护士长的工作!》——开发日志

正文 2024/6/28 23:00 终于整完啦!开导开导!定个时间发布,睡觉咯... 2024/6/28 接下来是调音时间!大概就是加个bgm,然后把声优大大们的声音跟人物动画手动对齐,必要时还得去网上搜一搜音效给加上...然后音量大小调整到-6到-12dB区间balabala... 有时候会遇到音频和自己做…

nchu-oop训练集7~8总结

一、前言 训练集的练习已经到达了尾声,通过这些训练集,我们将进一步加深对OOP概念的理解,并学会如何运用这些原则来设计和开发更加灵活、可维护、可扩展的软件系统。在程序中,我们学习如何模拟不同类型的电路组件,如电源、开关、插座、灯具等,以及它们之间的连接方式和电…

PTA题目集7-8的总结性Blog

一:前言: 1. 知识点总结: ①:递归的使用 ②:java面向对象类和对象的基本用法 ③:关联类,依赖类和组合等类间关系 ④:正则表达式的运用 ⑤:接口的基本使用 ⑥:Comparator接口及比较器基本使用 ⑦:ArrayList的基本使用 2. 题量: 较少,每次题目集只有1题 3. 难度: 由…