《WebKit 技术内幕》学习之八(3):硬件加速机制

3 其他硬件加速模块

3.1 2D图形的硬件加速机制

        其实网页中有很多绘图操作是针对2D图形的,这些操作包括通常的网页绘制,例如绘制边框、文字、图片、填充等,它们都是典型的2D绘图操作。在HTML5中,规范又引入了2D绘图的画布功能,它的作用是提供2D绘图的JavaScript接口,所以JavaScript代码可以很容易地调用该接口来绘制任意的2D图形。2D绘图本身是使用2D的图形上下文,而且一般使用软件方式来绘制它们,也就是光栅化(Rasterize)的方法。但是,其实这些2D绘图操作也可以使用GPU也就是3D绘图来完成,这里把使用GPU来绘制2D图形的方法称为2D图形的硬件加速机制。

        如上面所述,目前2D图形的硬件加速有两种应用场景,第一种就是网页基本元素的绘制,针对的层次类型其实在前面描述过,也就是ContentLayer,读者应该记得它的后端是一个2D的画布对象;第二种就是HTML5的新元素canvas,用来绘制2D图形。

3.1.1 2D图形上下文

        第7章中介绍了WebKit中的2D图形上下文,该上下文在WebKit的Chromium移植中需要使用Skia图形库来完成2D图形操作,图8-26描述了WebKit的Chromium移植中2D图形上下文的实现类。

                        图WebKit的Chromium移植使用Skia来绘制2D图形

        在上图中,对于WebKit需要使用GraphicsContext的地方,Chromium会创建一个Skia图形库中提供的SkCanvas对象来处理WebKit的2D图形操作请求。至于这个SkCanvas对象是使用软件绘图还是GPU绘图,取决于对SkCanvas对象的设置。SkCanvas类表示的是一个画布,2D的图形操作都是在这个画布上处理,绘制结果也是保存在SkCanvas对象中。如果调用者需要使用软件方式来绘图,如图中左半部分所示,那么调用者需要创建一个基本的SkDevice对象,该对象使用光栅扫描的方法来一一计算绘制的像素结果,并把结果存入SkBitmap对象中。SkBitmap对象使用一块CPU内存,该内存中保存的是一个个像素值,典型的例如RGBA格式。

        如果调用者需要使用GPU硬件来进行绘图,那么在创建SkCanvas对象的时候,通过传入SkSurface_Gpu对象即可。当然创建SkSurface_Gpu对象需要很多其他的对象,最重要的是SkGpuDevice对象,它是SkDevice的一个基类,同原先软件方式不同的是,它是将2D图形操作转变成对GL的操作,使用GrContext的3D图形上下文来绘制,并将结果存储在GrRenderTarget,该存储目标是GPU的内存缓冲区。

        从上面的讨论可以看出,WebKit调用GraphicsContext对象的时候,WebKit根本不知道下层实际使用的是软件还是GPU来绘制2D图形,这一切都是由Skia图形库来完成的,当需要启动硬件加速的时候,Chromium只需要为SkCanvas对象设置相应的对象即可。

3.1.2 Canvas 2D

        “canvas”是HTML5中新加入的元素,在最开始的时候它只是一个2D画布对象,网页开发者可以使用规范定义的JavaScript接口在画布上绘制任意的2D图形,这样的技术我们称之为Canvas 2D。不过,Khronous组织提出可以在该元素上使用JavaScript接口绘制3D图形,这样的技术我们称之为WebGL或者Canvas3D,这个稍后会做介绍。一个“canvas”元素的对象只能绘制2D图形和3D图形中的一种,不能够同时绘制这两者。

        “canvas”元素的“getContext”方法包含一个参数,该参数用来指定创建上下文对象的类型。对于2D的图形操作,通过传递参数值“2d”,浏览器会返回一个2D图形上下文,称为CanvasRenderingContext2D,它提供了用于绘制2D图形的各种应用程序编程接口,包括基本图形绘制(如线、矩形、圆弧)、文字绘制、图形变换、图片绘制及合成等。

        前面说到,CanvasRenderingContext2D是2D图形绘制的上下文对象,其提供了用于绘制2d图形的API,W3C工作组起草了标准的草案。该对象由JavaScript代码调用“getContext()”函数创建,Web开发者便可以调用它的编程接口在画布上绘制2D图形了。这些编程接口主要的作用就是在画布上绘制点、线、矩形、弧形、图片等,除此之外,还提供了这些绘制的样式和合成效果等。示例代码8-3给出了使用Canvas2D技术的基本方法。

        Canvas 2D可以使用软件方法来绘图,也可以使用GPU来加速绘图,根据前面介绍的2D图形上下文和Chromium中使用Skia图形库来绘图的方法,网页的Canvas 2D技术同样需要借助Skia这一技术。图8-27描述了Canvas 2D使用GPU来绘图所涉及的一些主要类。对于软件绘图来说,Chromium的工作过程实际上更简单一些,图中ImageBuffer只是使用SkCanvas、SkDevice和SkBitmap等类,这一过程其实不如硬件加速绘图复杂,所以这里不再赘述。

示例代码(使用Canvas2D技术的网页代码)

                                图(使用GPU硬件绘图的Canvas2D技术)

        HTML5的Canvas2D机制使用了一个GraphicsContext对象,也就是2D图形上下文,同时还包括一个ImageBuffer对象来表示canvas绘制的结果,这里软件绘图和GPU硬件加速绘图没有什么大的不同。回到GPU硬件绘图上来说,如果使用硬件加速机制的话,Chromium会创建一个SkDeferredCanvas对象,该对象的特别之处在于它采用延迟机制来绘制2D图形,随后介绍。该对象当然需要SkGpuDevice来将2D绘图操作转换为使用3D图形上下文来绘制,这一过程跟上一小节介绍的非常类似。笔者需要强调的是图中的Canvas2DLayerBridge类,它是一个桥接类,因为实际上2D图形是使用3D图形接口绘制的,所以Chromium需要3D图形上下文和一些准备工作,这些都是在该类中完成。

                WebGraphicsContext3DCommandBufferImpl类之后的部分跟图8-12介绍的过程完全一样,在这种情况下,上层是2D绘图还是3D绘图已经完全没有差别了。

        下面用三个阶段来描述Chromium是如何使用硬件加速绘图来支持HTML5的Canvas2D功能的,以示例代码8-3作为例子加以说明。首先看第一阶段。

        第一阶段这里称为初始化阶段,也就是示例代码(使用Canvas2D技术的网页代码)中调用“fillStyle”的阶段,因为该函数会触发建顺序图(Canvas2D初始化阶段的对象创中这些对象的创建。基本上,这一阶段的代码需要WebKit和Chromium创建图8-28所涉及类的对象,读者可以理解一下它们的顺序。其中GraphicsContext类主要是被CanvasRendering-Context2D类所使用,而GraphicsContext3D类是被Canvas2DLayerBridge类使用。这里面还需要强调的一点就是合成器中的CC::Layer(还包括WebLayer,限于图片太大,没有画出),它是由Canvas2DLayerBridge类创建,这听起来有点奇怪,因为CC::Layer类和GraphicsLayer类是一一对应的。不过没关系,因为在这里,“canvas”元素对应的RenderLayer对象还没有被创建,它在第二阶段才会创建,这是为什么呢?回想之前的介绍,在DOM创建过程中,当WebKit构建canvas元素的对象时,并没有为它创建RenderLayer对象,因为这是延迟执行的。如果“canvas”元素没有创建2D或者3D图形上下文,它是不需要RenderLayer对象的,当然也就没有RenderLayerBacking对象,更没有GraphicsLayer对象。同时,这段JavaScript代码在DOM构建过程中会被调用,这就造成了上面所述的这种情况。

        建顺序图(Canvas2D初始化阶段的对象创

        第二阶段是WebKit构建RenderLayer等对象。在DOM树构建完之后,WebKit会检查有无变化的CSS样式,在这里JavaScript代码改变了canvas元素的属性,所以WebKit会更新RenderObject树和RenderLayer树。图(为Canvas元素创建RenderLayer等并设置GraphicsLayer)描述了这一阶段。

                        图(为Canvas元素创建RenderLayer等并设置GraphicsLayer)

        在这里,笔者不想重复RenderLayer等对象的创建,而想重点强调GraphicsLayer对象如何设置自己的WebLayer成员变量。方法是这样的:WebKit中的RenderLayerBacking对象检查是否是canvas元素,如果是,RenderLayerBacking对象从HTMLCanvasElement对象中获得CanvasRenderingContext2D对象,这一上下文对象的platformLayer函数能够得到之前创建的WebLayer对象,这样WebKit就建立了RenderLayer和GraphicsLayer的映射关系。为了简洁起见,图中省略了一些步骤。

        第三个阶段就是绘图部分。图8-30详细描述了这一思想和主要过程。Chromium采用缓存模式来处理JavaScript代码的2D图形操作,也就是说,当JavaScript通过标准的接口调用2D图形的时候,Chromium使用SkDeferredCanvas对象保存2D图形操作,当Chromium需要绘制一个新帧的时候,Skia图形库才会一次性提交并绘制这些缓存的操作。

                        图(Chromium中的Canvas2D绘图过程)

        先看图中的上半部分,当JavaScript调用2D绘图接口时需要使用contextAcquired()函数获取2D图形上下文,Chromium据此判断后面修改画布的内容,所以Chromium会使用Canvas2DLayerManager类来设置一个TaskObserver对象到主消息循环,这样做的好处是等到JavaScript代码调用2D绘图接口之后,才会触发真正的绘图动作。而JavaScript代码调用的这些操作都是依靠SkDeferredCanvas来保存的。

        图中的下半部分表示当前面JavaScript调用2D绘图接口完毕后,WebKit调用TaskObserver类的didProcessTask方法。Canvas2DLayerManager类调用CanvasLayerBridge类来判断是否需要刷新那些操作。Canvas2DLayerBridge类检查并重置前面设置的标记,如果时机合适的话,该类调用SkDeferredCanvas类的flush函数提交前面保存的所有绘图操作,这样就完成了Canvas2D的绘制工作。

        当合成器调用updateLayers函数的时候,该函数会触发每个合成层绘制自己。因为Canvas2D机制是由JavaScript代码来绘制2D图形,所以这个时候canvas所在的合成层实际上已经绘制完成(或者说绘制操作已经缓存起来了)。图8-31描述了合成器要求绘制Canvas2D的合成层的过程,读者可以看到,这时候WebKit实际上不需要绘制该层,只需要改变一下3D图形上下文的状态。

                        图(Chromium中合成器调用绘制Canvas2D的合成层)

        从中读者可以发现,这一机制虽然延迟了一些操作(实际上没有什么影响),但是Chromium采用的这一延迟思想非常有用,也就是合并很多2D绘图操作 (5) ,这样能够有效提高绘制的性能。

3.2 WebGL

3.2.1 3D图形上下文

        前面提到过3D图形上下文,WebCore表示该上下文的抽象类是GraphicsContext3D。WebKit的Chromium移植定义了WebGraphicsContext3D接口,该接口类是GraphicsContext3D的实现类,基本上实现类的所有接口都可以映射到OpenGL ES 2.0 规范所定义的编程接口。

        图(3D图形上下文和Chromium的实现类)中包含了三个类,最下面的类就是WebGraphicsContext3DCommandBufferImpl,该类是WebGraphicsContext3D类对应的使用命令缓冲区的实现子类。前面提到的合成过程和Canvas2D,包括本节介绍的WebGL都会使用该类来实现3D图形操作。

                                图(3D图形上下文和Chromium的实现类)

3.2.2 WebGL的实现

        WebGL是Khronous组织提出的一套基于3D图形定义的JavaScript接口,它基于canvas元素,跟Canvas2D不同的是,Web开发者可以使用3D图形接口来绘制各种3D图形。根据WebGL规范中的描述,这些接口可以分成下面几个主要的部分。

  • 上下文及内容展示 :在使用WebGL的编程接口之前,开发者需要获取WebGL-RenderingContext和DrawingBuffer接口(Chromium需要它)。对JavaScript代码来说,GL的操作都是由WebGLRenderingContext对象来负责完成。但是,DrawingBuffer接口对用户来说是透明的,它用来存储渲染的内容并被合成器所合成,包括帧缓冲器对象(绘制的结果存储)和纹理对象(纹理被合成器所使用)。
  • WebGL的资源及其生命周期 :纹理对象、缓冲区(VBOs)、帧缓冲区、渲染缓冲区、着色器等(这些也都是OpenGL的资源)。它们有对应的JavaScript对象即与WebGLObject对应,这些对象的生命周期是一致的。
  • 安全 :WebGL规范为保证安全性,第一,所有的WebGL资源必须包含初始化的数据;第二,来源安全性,为防止信息泄露,当“canvas”元素的属性“origin-clean”为false时,readPixels将会抛出安全方面的异常;第三,要求所有的着色语言必须符合OpenGL ES Shading Language 1.0;第四,为防止DOS攻击,规范建议采取适当的措施对花费时间过长的渲染操作过程进行监控和限制。
  • WebGL接口 :主要包括各种资源类的接口和上下文类的接口,这些接口用于绘制3D的操作,它们基本上来源于OpenGL ES 2.0定义的接口。
  • WebGL与OpenGLES 2.0的区别 :这里不再一一介绍,读者可以自行翻阅和了解相关细节。读者假如想要了解自己的浏览器对WebGL支持的详细情况,请访问http://webglreport.sourceforge.net/获取详细参数。

        针对规范定义的内容,WebKit和Chromium定义了相应的类来描述它们,图8-33给出了主要类。WebGLRenderingContext类同CanvasRenderingContext2D类的作用类似,都是规范定义的接口。不同的是,WebGL的接口是3D图形操作。WebGLRenderingContext类同样需要一个GraphicsContext3D类和它的实现类,除此之外,还需要一个DrawingBuffer类,它类似于Canvas2D中的ImageBuffer,它的作用是保存WebGL渲染目标结果,WebKit将渲染结果用来合成。

                        图(WebKit和Chromium中支持WebGL的主要类)

        下面同样以例子来说明WebGL的工作过程,示例代码8-1中就是一个使用WebGL技术的网页,以此例为基础来描述这一个过程。跟Canvas2D的过程分析一样,这里同样也把Chromium中WebGL的工作过程分成三个阶段。

                第一阶段是对象的初始化阶段,当JavaScript引擎调用示例代码中的getContext函数的时候,WebKit就会执行如图8-34所示的对象创建顺序,这一过程跟Canvas2D的对象创建过程非常类似。不同的是,这一阶段不会创建CC::Layer对象。

                                图(WebGL初始化阶段的对象创建顺序)

        第二阶段是构建RenderLayer、WebLayer、CC::Layer等对象,同样是在DOM树构建之后检查CSS样式变化时才会被触发。当RenderLayer等对象被创建之后,WebKit设置GraphicsLayer对象所对应的WebLayer对象。同Canvas2D不一样的是,此时DrawingBuffer对象才会开始请求创建WebLayer(WebLayerImpl)和TextureLayer对象,之后WebKit同样将WebLayer对象设置到GraphicsLayer中。图8-35描述了这一过程,为了简洁起见,图中省略了一些步骤。

                        图(WebGL创建RenderLayer和TextureLayer等对象)

        第三阶段是3D绘图部分,图8-36是一个简单的WebGL使用clearColor接口来设置颜色的JavaScript代码被WebKit执行的过程。同Canvas2D机制不一样的是,每个GL的调用都是直接通过WebGraphicsContext3DCommandBufferImpl类将GL命令传给GPU进程,这一过程没有使用缓存机制,而是直接将命令传递给GPU进程。

                                                图(WebGL绘制3D图形)

         同样的,当合成器调用updateLayers函数的时候,该函数会触发WebGL所使用的合成层绘制合成层的目标结果到合成层的存储结果。WebGL所在层的内容在合成器请求更新该层之前已经由WebKit完成。图8-37描述了合成器要求绘制WebGL的合成层时候的过程,DrawingBuffer所要做的就是刷新3D图形上下文中的结果数据,并返回结果。

                                图(Chromium中合成器调用绘制WebGL的合成层)

3.3 CSS 3D变形

        CSS 3D变形和动画是HTML5引入的新特性,作用是能够对任意DOM子树作3D变形。这一特性非常有用,它同WebGL提供的能力是不一样的。WebGL是在一个“canvas”元素内部绘制3D图形,CSS 3D变形功能可以对任何元素进行3D变形,它是一个可以被元素子女继承的属性,也就是一个元素和它的子女都会作相应的3D变形。

        WebKit对应用该变形技术的DOM子树使用单独的合成层和硬件加速机制。当使用JavaScript代码改变该元素的3D变形样式后,Chromium能够减少网页每一帧渲染所需要的时间,典型的例子就是前面提到的网页,来自于www.famo.us。

         以示例代码6-1所展示的CSS 3D变形为例,说明3D变形是如何被WebKit和Chromium处理的。对于WebKit需要创建RenderLayer等对象,之前已经介绍过,这里不再赘述。图(设置合成器中的Layer对象的3D变形值)介绍了WebKit和Chromium设置3D变形值的过程。

                                图(设置合成器中的Layer对象的3D变形值)

        当网页中JavaScript代码修改元素的变换属性值的时候,通过上面的过程,最后样式是设置在该合成层(前景层)上,当WebKit将元素绘制完成之后,在合成过程中,WebKit通过3D变形作用到该合成层上,即可完成特定的效果。WebKit只是在第一次需要绘制“div”元素的内容,之后仅仅设置变换属性值,然后重新合成即可。当合成器调度绘制该合成层的时候,WebKit根本不会发生想象中的重新布局和重绘动作。虽然用户看起来网页内容在变动,但是这只是合成的动作,这些动画等都是WebKit和Chromium设计的机制和硬件加速带来的效果。

3.4 其他

        网页中还有很多其他的模块可以使用GPU硬件机制来加速,例如支持视频解码和播放、2D图形绘制等,WebKit支持它们的主要思想依旧是对这些内容进行分层,使用GPU的强大绘图能力来支持这些模块,关于视频方面的介绍,笔者将在第11章“多媒体”作进一步的阐述。读者还可以思考一下有没有其他地方可以使用加速机制。

        另外,还有很多新的思路对硬件加速机制进行改进,典型的做法是使用多线程机制,因为现代处理器都包含多核,使用线程化的方法来支持网页的渲染是一个很好的思路。当然线程化的代价就是WebKit需要同步或者内容的拷贝,例如前面介绍的线程化合成器、Layer树和LayerImpl树。Chromium为了减少同步和等待的开销,创建LayerImpl树并拷贝Layer树的内容,但是这一做法带来的好处也很明显。所谓有利也有弊正是如此,关键看应用场景的实际效果如何。

3.5 实践:Chromium的支持

        Chromium使用GPU加速机制来加速网页渲染被广泛地应用在各种网页中。Chromium浏览器对网页渲染的理解的确很不一样,在网页功能越来越强的同时,用户也能够取得较好的性能和体验效果。

        图(Chromium能够使用GPU加速的功能)描述了Chromium目前能使用GPU硬件加速的各项网页功能,这是在Windows系统上显示的结果,在其他平台上,结果可能不一样,例如在Android上面可能有更多跟加速相关的功能。图中的一些功能之前已经介绍过,例如Canvas、Compositing、3D CSS和CSS Animation、WebGL等。不过,还有些其他的功能笔者并没有介绍,例如Flash、Video、WebGL multisampling(WebGL中的反锯齿技术)等。除了Video之外,读者对其他功能有兴趣的话,可以自行参考相关材料。

                                图(Chromium能够使用GPU加速的功能)

        关于使用硬件加速和合成器的实践,读者可以回顾第2章中图2-5所描述的网页层次结构。相信读者现在对那些合成层,以及将合成层分成瓦片的理解更深了。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

枚举问题刷题

考研机试题目中的很多问题往往能通过暴力方法来求解,这些题目并不需要进行过多的思考,而只需枚举所有可能的情况,或者模拟题目中提出的规则,便可以得到解答。虽然说这种方法看上并不高明,但对于一些简单的题目来说却是…

力扣日记1.21-【回溯算法篇】77. 组合

力扣日记:【回溯算法篇】77. 组合 日期:2023.1.21 参考:代码随想录、力扣 终于结束二叉树了!听说回溯篇也是个大头,不知道这一篇得持续多久了…… 77. 组合 题目描述 难度:中等 给定两个整数 n 和 k&#…

最优传输学习及问题总结

文章目录 参考内容lam0.1lam3lam10lam50lam100lam300画图线性规划matlabpython代码 欢迎关注我们组的微信公众号,更多好文章在等你呦! 微信公众号名:碳硅数据 公众号二维码: 参考内容 https://blog.csdn.net/qq_41129489/artic…

Ubuntu下安装Gazebo仿真器

Ubuntu下安装Gazebo仿真器 Gazebo仿真平台通常需要配合ROS使用,因此需要先安装ROS。可以参考ROS安装教程 首先安装一些必要的工具 sudo apt-get update sudo apt-get install lsb-release wget gnupg修改源 sudo wget https://packages.osrfoundation.org/gazebo…

【教程】npm的时候ssh报错ssh://git@github.com/frozeman/bignumber.js-nolookahead.git

问题: fiscoubuntu:~/fisco/benchmarks$ npm install install web30.20.7 npm ERR! code 128 npm ERR! An unknown git error occurred npm ERR! command git --no-replace-objects ls-remote ssh://gitgithub.com/frozeman/bignumber.js-nolookahead.git npm ERR! …

UE5 Windows打包时报错“SDK Not Found”解决方案

在Unreal Engine 5.0.3 Windows平台下打包时报错:“Windows的SDK未正常安装,而其是生成数据的必需项。请检查主工具栏中“启动“菜单SDK部分来更新SDK。” 解决方案: 1、打开 Visual Studio Installer,点击“修改”按钮&#xf…

【技术分享】远程透传网关-单网口快速实现西门子S7-1200/1500 PLC程序远程上下载

准备工作 一台可联网操作的电脑一台单网口的远程透传网关及博达远程透传配置工具网线一条,用于实现网络连接和连接PLC一台西门子S7-1200/1500 PLC及其编程软件一张4G卡或WIFI天线实现通讯(使用4G联网则插入4G SIM卡,WIFI联网则将WIFI天线插入USB口&…

jieba.net使用NuGet管理器安装后初始化TfidfExtractor对象时报错

在引用安装jieba.net后,引用的Resources下只有如图几个文件 导致初始化TfidfExtractor时报错,报找不到 Could not find file E:\\TZKJNet\\robotindustry\\modules\\Tzkj.Superhard.SupplyDemand\\src\\Tzkj.Superhard.SupplyDemand.HttpApi.Host\\bin\\Debug\\net7.0\\Reso…

SpringSecurity(11)——核心组件和认证流程

获取用户信息 // 获取安全上下文对象,就是那个保存在 ThreadLocal 里面的安全上下文对象 // 总是不为null(如果不存在,则创建一个authentication属性为null的empty安全上下文对象) SecurityContext securityContext SecurityContextHolder.getContext(…

JS进阶-作用域、垃圾回收机制、闭包、变量提升(一)

• 作用域 作用域(scope)规定了变量能够被访问的“范围”,离开了这个“范围”变量便不能被访问 作用域分为: 局部作用域 全局作用域 • 局部作用域 局部作用域分为函数作用域和块作用域。 1. 函数作用域: 在函数内…

Kafka常见指令及监控程序介绍

kafka在流数据、IO削峰上非常有用,以下对于这款程序,做一些常见指令介绍。 下文使用–bootstrap-server 10.0.0.102:9092,10.0.0.103:9092,10.0.0.104:9092 需自行填写各自对应的集群IP和kafka的端口。 该写法 等同 –bootstrap-server localhost:9092 …

RabbitMQ数据隔离

1、新建用户 2、登录用户,设置虚拟主机 登录用户只能操作自己的虚拟主机,交换机等,不能操作其他人的!!!

【立创EDA-PCB设计基础】3.网络表概念解读+板框绘制

前言:本文对网络表概念解读板框绘制(确定PCB板子轮廓) 网络表概念解读 在本专栏的上一篇文章【嘉立创EDA-PCB设计指南】2,将设计的原理图转为了PCB,在PCB界面下出现了所有的封装,以及所有的飞线属性&…

MSI模块应用:可变N进制计数器设计

将集成组合逻辑电路模块和时序逻辑电路模块结合起来实现某种电路功能,一般多见于译码器、数据选择器和计数器的综合应用,以实现节拍信号发生器或序列信号发生器。本文介绍另一种题型,即数值比较器和计数器的综合应用。(典型试题&a…

最全笔记软件盘点!你要的笔记神器都在这里:手写笔记、知识管理、文本笔记、协作笔记等!

在当今的信息化社会中,人们对信息的处理速度越来越快,从工作到生活,我们都面临着大量信息的冲击。在这样的环境下,一个能够帮助我们管理、整理和储存信息的好工具显得尤为重要,而笔记软件恰恰可以满足这些需求。 在选…

在IDEA中使用快捷键让XML注释更加规范

Setting -> Editor -> Code Style -> XML 取消勾选 Line comment at first column 这样我们在使用ctrl / 快速注释时,就可以让注释符号紧贴注释内容,不出现空格。

vue+elementUI el-select 中 没有加clearable出现一个或者多个×清除图标问题

1、现象:下方截图多清除图标了 2、在全局common.scss文件中加一个下方的全局样式noClear 3、在多清除图标的组件上层div加noClear样式 4、清除图标去除成功

【C++进阶07】哈希表and哈希桶

一、哈希概念 顺序结构以及平衡树中 元素关键码与存储位置没有对应关系 因此查找一个元素 必须经过关键码的多次比较 顺序查找时间复杂度为O(N) 平衡树中为树的高度,即O( l o g 2 N log_2 N log2​N) 搜索效率 搜索过程中元素的比较次数 理想的搜索方法&#xff1a…

知识库是什么:中小型企业都要知道的重要讯息

在当今信息爆炸的年代,久而久之,企业可能发现自己沉浸在各种信息、学习资料和数据中。这就使得组织和管理这些信息变得尤为重要。进入我们的视线的就是“知识库”,它其实就像一个企业自己的“小图书馆”,只不过,这个库…

如何提取3D动画中的模型---模大狮模型网

在现代媒体制作和设计领域,3D动画已经成为一种常见的表达方式。如果您对一部3D动画中的某个特定模型非常感兴趣,并且想要提取出来以便进行后续操作或学习,模大狮将向您介绍一些方法和步骤。 一、选择适当的软件 要提取3D动画中的模型&#x…