写在前面:

客户端渲染

在Wayland架构中,客户端UI的所有呈现均由客户端代码执行,通常由客户端使用的图形工具包执行。

图形工具箱可以使用其希望呈现UI元素的任何方法:在CPU上进行软件呈现使用GLES进行硬件呈现。 Wayland所需要做的就是将客户端渲染的每一帧和窗口的结果像素发送到合成器。 像素数据可能以几种方式传输,具体取决于渲染方式以及客户端和合成器相互支持的内容:

  • 包含实际像素数据的共享内存缓冲区。 如果没有其他机制,则支持这些备用机制。
  • GPU缓冲区共享(DRM / DRI)。 客户端直接在GPU上渲染窗口,结果像素数据保留在GPU内存中,并将其句柄传递给合成器。 这防止了像素数据的不必要和昂贵的复制

合成器的工作

一旦合成器拥有了所有像素数据(或包含它的GPU缓冲区的句柄),它便可以合成一帧。 与客户端渲染一样,这可以通过几种方式完成:

  • 软件渲染。 CPU密集型,用作备用。 这还需要将像素数据从GPU内存中拉出,这很昂贵

  • 使用GLES进行完整的GPU渲染。 这将获取像素数据并在GPU上对其进行合成,如果动画需要的话,可能会应用着色器和3D转换。

  •   显示控制器上特定于硬件的API。 这些通常是2D合成API,与完整的3D计算相比,它们的资源占用较少,但仍在显示控制器而非CPU上进行处理,并且不需要额外的像素数据副本。[这个动作和crtc里面的合成不是一个概念]

例如,在传统的显卡上,可能有四个硬编码覆盖层:[weston的assign plane函数里面关于plane的分配基本基于下面的策略]

  • Primary: main overlay

    • By default surfaces belong to the primary plane

    • Only surfaces on the primary plane are composited with the renderer

  • Scanout: a single, full-screen surface
    • "Disables" composition for fullscreen clients
    • Very low overhead
  • Sprite: typically a video overlay in a different colour space
    • Use the hardware overlay
  • Cursor
    • Supports 64x64 surfaces
    • SHM only, contents are copied to an appropriate buffer

根据我从weston的assign_plane逻辑里面看到的一样,默认的view都是分给primary;cursor就是corsor,64x64;overlay就是单独的overlay;output_repaint会把所有的primary上的view交给gpu进行合成,变成scan-out;最后调用kms交给kernel

鼠标一个单独的cursor plane;video 占据sprite plane;

像素之旅

作为说明,请考虑一个UI元素从在客户端应用程序中以编程方式创建到出现在用户屏幕上的过程。假定通过将句柄传递给GPU资源(而不是客户端渲染中列出的其他方法)在客户端和合成器之间共享纹理。在本例中,我们使用Weston作为合成器。如果使用了Mutter,则将步骤5–7替换为一个步骤:使用GLES在GPU上合成所有表面,以形成最终的输出帧。

  1. 该程序使用其UI工具包创建一个新的小部件。

  2. 该工具包在其GLES上下文中设置了小部件,并将所有必要的纹理上传到GPU。

  3. 当应用程序接下来渲染帧时(例如,由于部分UI更改),它会通过GPU的GLES管道推送其GLES上下文,从而在GPU中创建一个包含整个应用程序窗口像素数据的输出纹理。
  4. 该应用程序使用Wayland协议向合成器(Weston)通知更新的窗口,并将GPU纹理句柄传递给weston。
  5. 当Weston接下来渲染框架时,它将确定是否需要对任何曲面应用GLES变换,并根据需要将曲面分配给平面和硬件叠加层。
  6. 对于每个平面,Weston会合成该平面中的所有曲面,从而创建该平面的输出像素数据。
    • 如果某个平面需要任何变换,则Weston渲染器将通过GPU GLES管道将该平面中的表面推入。
    • 如果不需要进行任何转换,或者可以使用更高效的特定于硬件的API来实现所需的转换,那么将跳过此步骤。
  7. Weston使用特定于硬件的API来组合所有平面以形成最终的输出框架。
  8. 输出帧将发送到用户的屏幕。

上面的图很好理解,如果是window composition,势必会跟在primary的plane上,那么就需要gpu把这些view变成一张full-screen的图,另外需要记得,合成完以后,像kernel传递的是这个gpu合成后的fd,而不是之前的多个view的fd;而如果本身就是full-screen或者overlay的,则并不需要这个合成的过程,所以两者在合成方面是有差异的

EGL 使用实践

EGL 的使用要遵循一些固定的步骤,按照这些步骤去配置、创建、渲染、释放。其中:
Display(EGLDisplay) 是对实际显示设备的抽象
Surface(EGLSurface)是对用来存储图像的内存区域 FrameBuffer 的抽象,包括 Color Buffer, Stencil Buffer ,Depth Buffer
Context (EGLContext) 存储 OpenGL ES绘图的一些状态信息1.创建与本地窗口系统的连接调用 eglGetDisplay 方法得到 EGLDisplay
2.初始化 EGL 方法调用 eglInitialize 方法初始化
3.确定渲染表面的配置信息调用 eglChooseConfig 方法得到 EGLConfig
4.创建渲染上下文通过 EGLDisplay 和 EGLConfig ,调用 eglCreateContext 方法创建渲染上下文,得到 EGLContext
5.创建渲染表面通过 EGLDisplay 和 EGLConfig ,调用 eglCreateWindowSurface 方法创建渲染表面,得到 EGLSurface
6.绘制表面使用 OpenGL ES API 绘制图形:gl_*()
7.绑定上下文通过 eglMakeCurrent 方法将 EGLSurface、EGLContext、EGLDisplay 三者绑定,接下来就可以使用 OpenGL 进行绘制了。
8.交换缓冲当用 OpenGL 绘制结束后,使用 eglSwapBuffers 方法交换前后缓冲,将绘制内容显示到屏幕上
9.释放 EGL 环境绘制结束,不再需要使用 EGL 时,取消 eglMakeCurrent 的绑定,销毁 EGLDisplay、EGLSurface、EGLContext。egl相关可以参考https://www.khronos.org/registry/EGL/sdk/docs/man/html/eglIntro.xhtml
https://glumes.com/post/opengl/opengl-egl-usage/
https://cloud.tencent.com/developer/article/1472434

如果对 EGLDisplay、EGLSurface 、EGLContext 这些抽象概念傻傻分不清楚,可以参考这幅图:

Wayland Requirements for OpenGL/ES

  1. Must support the following Native Display Types for eglGetDisplay():

    1. –wl_display for clients
    2. –gbm handle for Weston
  2. Must support the following EGL_EXTENSIONs:
    1. –EGL_KHR_image_pixmap
    2. –EGL_WL_bind_wayland_display
  3. Must support the following Native Pixmap Type for eglCreateImageKHR():
    1. –EGL_WAYLAND_BUFFER_WL
  4. Must support the following Wayland extension APIs:
    1. –eglBindWaylandDisplayWL
    2. –eglUnbindWaylandDisplayWL
    3. –eglQueryWaylandBufferWL
  1. Use eglGetPlatformDisplayEXT in concert with EGL_PLATFORM_WAYLAND_KHR to create an EGLdisplay.
  2. Configure the display normally, choosing a config appropriate to your circumstances with EGL_SURFACE_TYPE set to EGL_WINDOW_BIT .
  3. Use wl_egl_window_create to create a wl_egl_window for a given wl_surface .
  4. Use eglCreatePlatformWindowSurfaceEXT to create an EGLSurface for a wl_egl_window .
  5. Proceed using EGL normally, e.g. eglMakeCurrent to make current the EGL context for your surface and eglSwapBuffers to send an up-to-date buffer to the compositor and commit the surface.

https://ppaalanen.blogspot.com/2012/03/what-does-egl-do-in-wayland-stack.html : pq 是weston/wayland开发者一员,非常资深。看最近博客貌似打算在Wayland上面支持HDR

Wayland serverThe Wayland server in the diagram is Weston with the DRM backend. The server does its
rendering using GL ES 2, which it initialises by calling EGL. Since the server runs on
"bare KMS", it uses the EGL DRM platform, which could really be called as the GBM
platform, since it relies on the Mesa GBM interface. Mesa GBM is an abstraction of the
graphics driver specific buffer management APIs (for instance the various libdrm_*
libraries), implemented internally by calling into the Mesa GPU drivers.Mesa GBM provides graphics memory buffers to Weston. Weston then uses EGL calls to bindthem into GL objects, and renders into them with GL ES 2. A rendered buffer is shown on
an output (monitor) by queuing a page flip via the libdrm KMS API.If the EGL implementation offers the extension EGL_WL_bind_wayland_display, Weston will
use it to register its wl_display object (facing the clients) to EGL. In practice, the
Mesa EGL then adds a new global Wayland object to the wl_display. That object (or
interface) is called wl_drm, and the server will automatically advertise that to all
clients. Clients will use wl_drm for DRM authentication, getting the right DRM device
node, and sharing graphics buffers with the server without copying pixelsWayland clientA Wayland client, naturally, connects to a Wayland server, and gets the main Wayland
protocol object wl_display. The client creates a window, which is a Wayland object of
type wl_surface. All what follows is enabled by the Wayland platform support in Mesa EGL.The client passes the wl_display object to eglGetDisplay() and receives an EGLDisplay to
be used with EGL calls. Then comes the trick that is denoted by the double-arrowed blue
line from Wayland client to Mesa EGL in the diagram. The client calls the wayland-egl API
(implemented in Mesa) function wl_egl_window_create() to get the native window handle.
Normally you would just use the "real" native window object wl_surface (or an X11 Window
if you were using X). The native window handle is used to create the EGLSurface EGL
handle. Wayland has this extra step and the wayland-egl API because a wl_surface carries
no information of its size. When the EGL library allocates buffers, it needs to know the
size, and wayland-egl API is the only way to tell that.Once EGL Wayland platform knows the size, it can allocate a graphics buffer by calling
the Mesa GPU driver. Then this graphics buffer needs to be mapped into a Wayland protocol
object wl_buffer. A wl_buffer object is created by sending a request through the wl_drm
interface carrying the name of the (DRM) graphics buffer. In the server side, wl_drm
requests are handled in the Mesa EGL library, where the corresponding server side part of
the wl_buffer object is created. In the diagram this is shown as the blue dotted arrow
from EGL Wayland platform to itself. Now, whenever the wl_buffer object is referenced in
the Wayland protocol, the server knows exactly what it is.The client now has an EGLSurface ready, and renders into it by using one of the GL APIs
or OpenVG offered by Mesa. Finally, the client calls eglSwapBuffers() to show the result
in its Wayland window.The buffer swap in Mesa EGL Wayland platform uses the Wayland core protocol and sends an
attach request to the wl_surface, with the wl_buffer as an argument. This is the blue
dotted arrow from EGL Wayland platform to Wayland server.Weston itself processes the attach request. It knows the buffer is not a shm buffer, so
it passes the wl_buffer object to the Mesa EGL library in an eglCreateImageKHR() function
call. In return Weston gets an EGLImage handle, which is then turned into a 2D texture,
and used in drawing the surface (window). This operation is enabled by
EGL_WL_bind_wayland_display extension.SummaryThe important facts, that should be apparent in the diagram, are:
•There are two different EGL platforms in play: one for the server, and one for the
clients.
•A Wayland server does not contain any graphics hardware or driver specific code, it is
all in the generic libraries of DRM, EGL and GL (libdrm and Mesa).
•Everything about wl_drm is an implementation detail internal to the EGL library in use.
The system dependent part of Weston is the backend, which somehow must be able to drive
the outputs. The new abstractions in Mesa (GBM API) make it completely hardware agnostic
on standard Linux systems. Therefore every Wayland server implementation does not need
its own set of graphics drivers, like X does.It is also worth to note, that 3D graphics on X uses very much the same drivers as
Wayland. However, due to the Wayland requirements from the EGL framework (extensions, EGL
Wayland platform), proprietary driver stacks need to specifically implement Wayland
support, or they need to be wrapped into a meta-EGL-library, that glues Wayland support
on top. Proprietary drivers also need to provide a way to use accelerated graphics
without X, for a Wayland server to run without X beneath. Therefore the desktop
proprietary drivers like Nvidia's have a long way to go, as currently nvidia does not
implement EGL at all, no support for Wayland, and no support for running without X, or
even setting a video mode without X.Due to the way wl_drm is totally encapsulated into Mesa EGL and how the interfaces are
defined for the EGL Wayland platform and the EGL extension, another EGL implementor can
choose their very own way of sharing graphics buffers instead of using wl_drm.There are already plans to change to some of the architecture described in this article,
so it is possible that details in the diagram become outdated fairly soon. This article
also does not consider a purely software rendered Wayland stack, which certainly would
lift all these requirements, but quite likely be too slow in practice for the desktop.

客户机将wl_display对象传递给eglGetDisplay(),并接收EGLDisplay,以便与EGL调用一起使用。然后是图中从Wayland客户端到Mesa EGL的双箭头蓝线所表示的技巧。客户端调用wayland-egl API(在Mesa中实现)函数wl_egl_window_create()来获得本机窗口句柄。通常,你只需要使用“真实的”本机窗口对象wl_surface(或者使用X的X11窗口)。本机窗口句柄用于创建EGLSurface EGL句柄。Wayland有这个额外的步骤和Wayland -egl API,因为wl_surface不携带它的大小信息。当EGL库分配缓冲区时,它需要知道缓冲区的大小,而wayland-egl API是告诉这个的唯一方法。一旦EGL Wayland平台知道了大小,它就可以通过调用Mesa GPU驱动程序来分配图形缓冲区。然后这个图形缓冲区需要映射到一个Wayland协议对象wl_buffer。通过携带(DRM)图形缓冲区名称的wl_drm接口发送请求来创建wl_buffer对象。在服务器端,wl_drm请求在Mesa EGL库中处理,在该库中创建wl_buffer对象的相应服务器端部分。在图中,这显示为从EGL Wayland平台到它自身的蓝色虚线箭头。现在,只要wl_buffer对象在Wayland协议中被引用,服务器就会确切地知道它是什么。客户端现在已经准备好了一个EGLSurface,并通过使用Mesa提供的GL api或OpenVG来呈现它。最后,客户端调用eglSwapBuffers()在其Wayland窗口中显示结果。Mesa EGL Wayland平台中的缓冲区交换使用Wayland核心协议,并以wl_buffer作为参数向wl_surface发送attch请求。这是从EGL Wayland平台到Wayland服务器的蓝色虚线箭头。Weston本身处理attch请求。它知道缓冲区不是shm缓冲区,所以它通过eglCreateImageKHR()函数调用将wl_buffer对象传递给Mesa EGL库。作为回报,Weston获得一个EGLImage手柄,然后将其转换为2D纹理,并用于绘制表面(窗口)。该操作由EGL_WL_bind_wayland_display扩展名启用。

根据pq的文章可以知道,buffer是在weston_platform_create_egl_surface里面实现的。可以看到这个函数用到了window->native,于pq的文章说明一致。
eglswapbuffers会调用surface_attch.
如上所述也就和我们通过weston-debug观察到的现象一致。
另外,看样子simple-egl的最终绘图结果只是texture。

simple-egl.c

关于EXT扩展egl函数说明:https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_platform_base.txt
main
{
a.. init_egl(&display, &window);weston_platform_get_egl_display//基于wayland的平台,获取egl display对象 [egl实践1.]eglGetDisplay / eglGetPlatformDisplayEXT             //get EGLDisplayreturn eglGetDisplay((EGLNativeDisplayType) native_display);//使用EGL中的函数eglGetDisplay(),并向EGL提供强制转换为NativeDisplayType指针的wl_display指针eglInitialize                                                       //[egl实践2.]eglBindAPI(EGL_OPENGL_ES_API);eglGetConfigs  //获取属性eglChooseConfig//选择属性      //get EGLConfig                      //[egl实践3.]eglGetConfigAttrib//获取属性资源,获取color buffer位宽eglCreateContext              //get EGLContext                     //[egl实践4.]eglQueryStringweston_check_egl_extension(extensions, "EGL_EXT_buffer_age")//判断是否支持weston_check_egl_extension(extensions, "EGL_EXT_swap_buffers_with_damage")//判断是否支持weston_check_egl_extension(extensions, "EGL_KHR_swap_buffers_with_damage")//判断是否支持b..   create_surface(&window);wl_compositor_create_surface  //get wl_surfacewl_egl_window_create          //get wl_egl_windowwindow->native =wl_egl_window_create(window->surface,window->geometry.width,window->geometry.height);//调用要wl_egl_window_create()使用的surface以及其大小来获取wl_egl_window指针。weston_platform_create_egl_surface //get EGLSurfaceeglCreateWindowSurface   / eglCreatePlatformWindowSurfaceEXT    //[egl实践5.],这里会把实际的buffer和wl_buffer绑定return eglCreateWindowSurface(dpy, config,(EGLNativeWindowType) native_window,attrib_list);//它将wl_egl_window指针转换为NativeWindowType指针,并将其传递给eglCreateWindowSurface(); wl_egl_window的相关处理函数在wayland-egl-core.c中实现,改变窗口大小等操作xdg_wm_base_get_xdg_surface   //get xdg_surfacexdg_surface_get_toplevel      //get xdg_toplevelwl_surface_commit             //一次commit。把其他相关属性除了buffer以外的内容commit一次eglMakeCurrent                                                     //[egl实践7.]if (!window->frame_sync)eglSwapInterval(display->egl.dpy, 0);                        //eglSwapInterval用于设置buffer交换时的最小帧数,默认为1;如果interval设置为0,则缓冲区交换不会同步到视频帧,只要渲染完成,交换就会发生。
所以跑weston-simple-egl -b 0;意味着,不等weston的vsync同步,纯gpu绘画,绘画完成就交换前端和后端缓冲区c..   init_gl(&window);frag = create_shader(window, frag_shader_text, GL_FRAGMENT_SHADER);// 创建片元着色器vert = create_shader(window, vert_shader_text, GL_VERTEX_SHADER);  // 创建顶点着色器program = glCreateProgram();         // 创建着色器程序glAttachShader(program, frag);       // 向程序中加入片元着色器glAttachShader(program, vert);       // 向程序中加入顶点着色器glLinkProgram(program);              // 链接程序,使上述操作生效  glGetProgramiv                       // 获取program的链接情况glUseProgram(program);               //加载并使用链接好的程序glBindAttribLocation(program, window->gl.pos, "pos");//手动为name为pos的attribute变量设置地址索引window->gl.posglBindAttribLocation(program, window->gl.col, "color");//手动为name为color的attribute变量设置地址索引window->gl.colglLinkProgram(program);              // 链接程序,使上述操作生效  window->gl.rotation_uniform = glGetUniformLocation(program, "rotation");//获取一致变量rotation在着色器程序中的位置序号,通过该序号可以设置一致变量的值,如果没有该变量则返回-1/* The mainloop here is a little subtle.  Redrawing will cause* EGL to read events so we can just call* wl_display_dispatch_pending() to handle any events that got* queued up as a side effect. */while (running && ret != -1) {if (window.wait_for_configure) {ret = wl_display_dispatch(display.display);      //https://www.systutorials.com/docs/linux/man/3-wl_display_dispatch/} else {ret = wl_display_dispatch_pending(display.display);//处理完server过来的排在队列的消息。随后重画
d..         redraw(&window, NULL, 0);                                   //[egl实践6.绘画]glViewport(0, 0, window->geometry.width, window->geometry.height);glUniformMatrix4fv(window->gl.rotation_uniform, 1, GL_FALSE,(GLfloat *) rotation);glClearColor(0.0, 0.0, 0.0, 0.5);glClear(GL_COLOR_BUFFER_BIT);glVertexAttribPointer(window->gl.pos, 2, GL_FLOAT, GL_FALSE, 0, verts);glVertexAttribPointer(window->gl.col, 3, GL_FLOAT, GL_FALSE, 0, colors);glEnableVertexAttribArray(window->gl.pos);glEnableVertexAttribArray(window->gl.col);glDrawArrays(GL_TRIANGLES, 0, 3);glDisableVertexAttribArray(window->gl.pos);glDisableVertexAttribArray(window->gl.col);                display->swap_buffers_with_damage / eglSwapBuffers        //[egl实践8.交换缓冲];会做attch/damage/commit}}
}
因为最开始在创建egldisplay以及eglsurface的时候和wayland的display以及surface关联,故eglSwapBuffer应该会让weston有所动作。我还没找到gpu如何把handler传给weston的地方

https://www.apertis.org/waylandevaluation/compositors/

https://events.static.linuxfound.org/sites/events/files/slides/als2015_wayland_weston_v2.pdf

https://blog.csdn.net/u012839187/article/details/107403974

接下篇:https://blog.csdn.net/u012839187/article/details/113104654

======

drm_assign_planes

drm_output_propose_state   设置plane和view之间的关系,并且调用drm_pending_state_test[atomic_test]确认这个状态是否能atomic

drm_output_prepare_plane_view

drm_fb_get_from_view     //重要,如果是wl_shm_buffer则跳过;否则获取drm_fd;从view中拿到drm_fd并且将drm_fd和buffer关联;返回drm_fd

drm_output_try_view_on_plane

drm_pending_state_test

drm_pending_state_apply_atomic         // enable or disable crtc active状态  &  atomic commit在调用完下面函数以后

drm_output_apply_state_atomic    //setprop for output

int wl_display_roundtrip (struct wl_display *display)

Block until all pending request are processed by the server

The main queue is dispatched by calling wl_display_dispatch(). This will dispatch any events queued on the main queue and attempt to read from the display fd if its empty. Events read are then queued on the appropriate queues according to the proxy assignment. Calling that function makes the calling thread the main thread.

wl_display_dispatch实现

1.wl_display_flush
2.wl_display_poll
3.wl_display_read_events

1.dispatch把对应的消息通过socket发给server

2.dispatch拿到server发来的消息,分发出去

3.frame_listener拿到对应的frame_done消息,执行redraw

4.redraw把对应的消息打包好,通过dispatch发给server

如果不在这个规定的心跳里面更新呢?会造成显示不稳定。我尝试在simple-shm的dispatch里面更新buffer,显示闪烁(我画了一个白屏)

循环

display:weston:weston-simple-egl相关推荐

  1. Openharmony之GPU Mesa3D移植一(weston 老框架)

    目录 1.获取openharmony rk分支版本代码 2.编译5.10内核 1)修改DTS 2)修改config配置 3)修改drivers/gpu/drm/drm_ioctl.c 4)编译 5)刷 ...

  2. 在Ubuntu上基于wayland/weston源码构建weston桌面

    Ubuntu构建weston桌面 简介 下载工具/库 安装ninja 设置环境变量 构建wayland 构建wayland-protocols 构建weston 运行weston weston的一些测 ...

  3. 02-编译weston demo

    参考链接:Building Weston https://gitee.com/slamdunk1016/weston_demo.git 1.首先设置环境变量 写个简单的set-env.sh脚本方便运行 ...

  4. 【架构分析】Weston Inside - 基础数据结构详解

    Weston Weston是Wayland compositor的参考实现,广泛应用与AGL和GENIVI 车机Linux系统,各个版本的weston代码可以在 https://github.com/ ...

  5. Wayland/Weston 启动方式简介

    前言 本文简单介绍 Weston 常用的几种 backend 启动方式.目前最新的 Weston 8.0.0 支持如下几种 backend: drm-backend fbdev-backend hea ...

  6. weston 配置文件去掉状态工具栏

    我们在自己的板子上使用wayland作为图形显示器,但是在启动应用时会先启动weston桌面,如下图所示: 我们希望不显示该weston桌面而直接进入到自己的应用中去,那么我们可以通过配置weston ...

  7. 嵌入式桌面(1)——weston桌面

    weston参考文档: https://www.mankier.com/5/weston.ini https://www.mankier.com/7/weston-drm http://manpage ...

  8. 修改weston桌面背景

    背景 linux开发板采用weston桌面系统, 希望修改默认桌面图片: 结果 在/etc/xdg/weston/weston.ini中新增: [shell] panel-location=botto ...

  9. EGL Off-Screen rendering using GBM

    https://blog.csdn.net/weixin_42263483/article/details/100576577 最近研究EGL的off-screen rendering,特别是使用GB ...

最新文章

  1. Java堆栈功能_【ThinkingInJava】35、用java实现堆栈功能
  2. 倒排索引优化 - 跳表求交集 空间换时间 贪心
  3. Linux下CMake简明教程(10) 定义宏来控制打印的信息
  4. 深度探秘 Java 8 函数式编程(下)
  5. 204787 ,194787 |0001 1131 0001 4226 7035 ![2480 ]
  6. thinkphp三级分销小程序源码_山东谷道微信小程序商城源码带后台 公众号平台三级分销系统...
  7. Python学习笔记之字典(一)
  8. 停止使用C#异步流保存到磁盘
  9. Thinkphp5中利用js/jQuery传递参数的方法
  10. JNI 在实际项目中的使用方法
  11. Ubuntu18.04解决Teamview检测为商用问题
  12. Mat 转 IplImage
  13. 信息检索的基本方法(1)
  14. SWAT 建模与案例应用
  15. 【学习笔记】汇编语言入门
  16. java StringBuilder用法,用逗号拼接字符串 zhaoqian,sunli,zhouwu
  17. 从低位开始取出长整型变量s中奇数位上的数依次构成一个新数放在t中
  18. 椭圆是一个凸集的证明
  19. STM32F1串口最高波特率问题
  20. C# DES加密解密算法

热门文章

  1. 电脑怎样设置桌面待办,桌面待办事项软件
  2. 先验分布、后验分布、共轭分布、共轭先验分布、
  3. jQuery中的append()方法
  4. Java生鲜电商平台-订单架构实战
  5. Synchronization和java内存模型
  6. java架构模式与设计模式(四)--事件风暴
  7. 基于Ubuntu系统,调用opencv在图片上显示数字和汉字
  8. vue-element-admin动态加载接口和报错解决
  9. Vue+Element UI完成新建调查问卷
  10. python opencv 直方图均衡_深入理解OpenCV+Python直方图均衡化