https://blog.csdn.net/weixin_42263483/article/details/100576577

最近研究EGL的off-screen rendering,特别是使用GBM这块,网上资料很少。综合搜集到的资料,整合了一个小demo。很多注意事项都写在代码注释里面了。

EGL Spec的介绍,没有提及如何使用GBM进行off-screen rendering。因为这属于native platform的实现。
EGLSurfaces:
1. windows: used for onscreen rendering
2. pbuffers: used for offscreen rendering
3. pixmaps: used for offscreen rendering into buffers that may be accessed through native APIs.
EGL windows and pixmaps are tied to platform windows and pixmaps.
EGL supports off-screen rendering surfaces in pbuffers. Pbuffers differ from windows in the followings ways:
1. Pbuffers are typically allocated in offscreen(non-visible) graphics memory and are intended only for accelerated
   offscreen rendering.
2. Pbuffers are EGL resources and have no associated native window or native window type. It may not by possible to
   render to pbuffers using native rendering APIs.

更多参考资料:
https://www.khronos.org/registry/EGL/extensions/MESA/EGL_MESA_platform_gbm.txt
This extension defines how to create EGL resources from native GBM resources using the functions defined by EGL_EXT_platform_base.
(GBM is a Generic Buffer Manager for Linux).

https://www.khronos.org/registry/EGL/extensions/KHR/EGL_KHR_platform_gbm.txt  (EGL 1.5 is required.)
This extension defines how to create EGL resources from native GBM resources using the EGL 1.5 platform functionality
(GBM is a Generic Buffer Manager for Linux).

EGL/GBM does not support Pbuffers. It doesn't support Pixmaps either.
To create an offscreen surface with EGL/GBM, you must pass a gbm_surface to eglCreateWindowSurface. "Window" is a misnomer.
No real "window" gets created. The resultant buffer will remain offscreen unless you use the kernel's KMS APIs to post it to the display.
// eglGetDisplay((EGLNativeDisplayType)my_gbm_device);
// eglCreateWindowSurface(egl_dpy, egl_config, (EGLNativeWindowType)my_gbm_surface, NULL);
or
// eglGetPlatformDisplayEXT(EGL_PLATFORM_GBM_MESA, my_gbm_device, NULL);
// eglCreatePlatformWindowSurfaceEXT(egl_dpy, egl_config, my_gbm_surface, NULL);

/* A really good sample code */
http://virtuousgeek.org/blog/index.php/jbarnes/2011/10/31/writing_stanalone_programs_with_egl_and_
https://github.com/eyelash/tutorials/blob/master/drm-gbm.c

https://www.khronos.org/registry/EGL/sdk/docs/man/html/eglIntro.xhtml
————————————————

/******************************************************************************************** Compile CMD: gcc -g -o SimpleGBMDemo SimpleGBMDemo.c -ldrm -lgbm -lEGL -lGL -I/usr/include/libdrm* * Dependency: mesa-dev, libdrm-dev, libgbm-dev* * On-Screen  rendering: rendering into a window.* Off-Screen rendering: off-screen interface is used for rendering into user-allocated memory *                       without any sort of window system or operating system dependencies.* * Generic Buffer Management (GBM) is an API that provides a mechanism for allocating buffers for * graphics rendering tied to Mesa. GBM is intended to be used as a native platform for EGL on drm * or openwfd. The handle it creates can be used to initialize EGL and to create render target buffers.* * EGL is a application API.* DRI is 'Direct Rendering Infrastructure'. It's part of Linux's graphic acceleration driver stack.* Hardward <--> Linux Kernel DRM driver <--DRI Protocol--> userspace Driver <--APP APIs--> Applications.* * WARNING: Nvidia proprietary driver doesn't support DRM/DRI. So this demo not work on Nvidia GPU.* * *****************************************************************************************/#include <xf86drm.h>
#include <xf86drmMode.h>
#include <gbm.h>
#include <EGL/egl.h>
#include <GL/gl.h>
#include <stdlib.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>#define EXIT(msg) { fputs (msg, stderr); exit (EXIT_FAILURE); }void assertEGLError(const char *msg)
{EGLint error = eglGetError();if(error != EGL_SUCCESS) {printf("EGL error 0x%x at %s\n", error, msg);}
}static int g_device_fd;static uint32_t connector_id;
static drmModeModeInfo mode_info;
static drmModeCrtc *crtc;
static struct gbm_device *gbm_device;static EGLDisplay display;
static EGLContext context;
static struct gbm_surface *gbm_surface;
static EGLSurface egl_surface;static struct gbm_bo *previous_bo = NULL;
static uint32_t previous_fb;static void swap_buffers () {eglSwapBuffers (display, egl_surface);struct gbm_bo *bo = gbm_surface_lock_front_buffer (gbm_surface);uint32_t handle = gbm_bo_get_handle (bo).u32;uint32_t pitch = gbm_bo_get_stride (bo);uint32_t fb;drmModeAddFB (g_device_fd, mode_info.hdisplay, mode_info.vdisplay, 24, 32, pitch, handle, &fb);drmModeSetCrtc (g_device_fd, crtc->crtc_id, fb, 0, 0, &connector_id, 1, &mode_info);if (previous_bo) {drmModeRmFB (g_device_fd, previous_fb);gbm_surface_release_buffer (gbm_surface, previous_bo);}previous_bo = bo;previous_fb = fb;
}static void draw (float progress) {glClearColor (1.0f-progress, progress, 0.0, 1.0);glClear (GL_COLOR_BUFFER_BIT);swap_buffers ();
}static void clean_up () {// set the previous crtcdrmModeSetCrtc (g_device_fd, crtc->crtc_id, crtc->buffer_id, crtc->x, crtc->y, &connector_id, 1, &crtc->mode);drmModeFreeCrtc (crtc);if (previous_bo) {drmModeRmFB (g_device_fd, previous_fb);gbm_surface_release_buffer (gbm_surface, previous_bo);}eglDestroySurface (display, egl_surface);gbm_surface_destroy (gbm_surface);eglDestroyContext (display, context);eglTerminate (display);gbm_device_destroy (gbm_device);
}/* On-Screen Rendering */
void print_default_display_info()
{int major, minor;EGLDisplay defaultDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);assertEGLError("eglGetDisplay(EGL_DEFAULT_DISPLAY)");eglInitialize (defaultDisplay, &major, &minor);assertEGLError("eglInitialize");printf("*************EGL %d.%d when eglGetDisplay(EGL_DEFAULT_DISPLAY)********t*****\n", major, minor);printf(" EGL_CLIENT_APIS: %s\n", eglQueryString(defaultDisplay, EGL_CLIENT_APIS));printf(" EGL_VENDOR: %s\n", eglQueryString(defaultDisplay,  EGL_VENDOR));printf(" EGL_VERSION: %s\n", eglQueryString(defaultDisplay,  EGL_VERSION));printf(" EGL_EXTENSIONS: %s\n", eglQueryString(defaultDisplay,  EGL_EXTENSIONS));eglTerminate (defaultDisplay);assertEGLError("eglTerminate");printf("\n");
}static void find_display_configuration ()
{drmModeRes *resources = drmModeGetResources (g_device_fd);/* It will crash if GPU driver doesn't support DRM/DRI. */assert(!(resources == NULL));// find a connectordrmModeConnector *connector = NULL;for (int i=0; i < resources->count_connectors; i++) {drmModeConnector *temp_connector = drmModeGetConnector (g_device_fd, resources->connectors[i]);// pick the first connected connectorif (temp_connector->connection == DRM_MODE_CONNECTED) {connector = temp_connector;break;}drmModeFreeConnector (connector);}if (!connector) EXIT ("no connector found\n");// save the connector_idconnector_id = connector->connector_id;// save the first modemode_info = connector->modes[0];printf ("resolution: %ix%i\n", mode_info.hdisplay, mode_info.vdisplay);// find an encoderdrmModeEncoder *encoder = NULL;if (connector->encoder_id) {encoder = drmModeGetEncoder (g_device_fd, connector->encoder_id);}if (!encoder) EXIT ("no encoder found\n");// find a CRTCif (encoder->crtc_id) {crtc = drmModeGetCrtc (g_device_fd, encoder->crtc_id);}// clean updrmModeFreeEncoder (encoder);drmModeFreeConnector (connector);drmModeFreeResources (resources);
}int main ()
{/* For comparing with Off-Screen Rendering Info */print_default_display_info();/* Off-Screen Rendering */printf("************/dev/dri/card0************\n");g_device_fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK);find_display_configuration ();/* Create EGL Context using GBM */int major, minor;gbm_device = gbm_create_device (g_device_fd);display = eglGetDisplay (gbm_device);eglInitialize (display, &major, &minor);printf("*************EGL %d.%d when eglGetDisplay(GBM)*************\n", major, minor);printf(" EGL_CLIENT_APIS: %s\n", eglQueryString(display, EGL_CLIENT_APIS));printf(" EGL_VENDOR: %s\n", eglQueryString(display,  EGL_VENDOR));printf(" EGL_VERSION: %s\n", eglQueryString(display,  EGL_VERSION));printf(" EGL_EXTENSIONS: %s\n", eglQueryString(display,  EGL_EXTENSIONS));eglBindAPI (EGL_OPENGL_API);EGLint attributes[] = {EGL_RED_SIZE, 8,EGL_GREEN_SIZE, 8,EGL_BLUE_SIZE, 8,EGL_NONE };EGLConfig config;EGLint num_config;eglChooseConfig (display, attributes, &config, 1, &num_config);context = eglCreateContext (display, config, EGL_NO_CONTEXT, NULL);// create the GBM and EGL surfacegbm_surface = gbm_surface_create (gbm_device, mode_info.hdisplay, mode_info.vdisplay, GBM_BO_FORMAT_XRGB8888, GBM_BO_USE_SCANOUT|GBM_BO_USE_RENDERING);egl_surface = eglCreateWindowSurface (display, config, gbm_surface, NULL);eglMakeCurrent (display, egl_surface, egl_surface, context);/* Rendering using OpenGL... */int i;for (i = 0; i < 600; i++)draw (i / 600.0f);clean_up ();close (g_device_fd);return 0;
}

http://virtuousgeek.org/blog/index.php/jbarnes/2011/10/31/writing_stanalone_programs_with_egl_and_

Both on dri-devel and at the most recent Kernel Summit, the idea of a KMS based console program came up yet again. So in the interest of facilitating the lazyweb to write one, I thought I’d provide a review of what it takes to write a simple KMS program that ties in with GL, just in case anyone wants to port the VTE widget and give me my VTs on a cube. :) The ideal situation would be one where a distro could set CONFIG_VT=n and have userspace provide all console services, including support for the various types of input and output that exist in the wild today. The only thing that ought to be left to the kernel is spitting out panic information somehow. That means having a very simple text drawing layer remain, and a way for the kernel to flip to the latest kernel console buffer (today these functions are provided by fbcon and the DRM KMS layer, but if a userspace console service existed, we could likely clean them up quite a bit, and remove the need for the full VT and fb layers to be compiled in).

Initialization

One of the first things any DRM based program must do is open the DRI device:

int fd;
fd = open("/dev/dri/card0", O_RDWR);

You’ll need to save that fd for use with any later DRM call, including the ones we’ll need to get display resources. The path to the device may vary by distribution or configuration (e.g. with a multi-card setup), so take care to report sensible error strings if things go wrong.

The next step is to initialize the GBM library. GBM (for Generic Buffer Management) is a simple library to abstract buffers that will be used with Mesa. We’ll use the handle it creates to initialize EGL and to create render target buffers.

struct gbm_device *gbm;
gbm = gbm_create_device(fd);

Then we get EGL into shape:

EGLDisplay dpy;
dpy = eglGetDisplay(gbm);

We’ll need to hang on to both the GBM device handle and the EGL display handle as well, since most of the calls we make will need them. What follows is more EGL init.

EGLint major, minor;
const char *ver, *extensions;
eglInitialize(dpy, &major, &minor);
ver = eglQueryString(dpy, EGL_VERSION);
extensions = eglQueryString(dpy, EGL_EXTENSIONS);

Now that we have the extensions string, we need to check and make sure the EGL_KHR_surfaceless_opengl extension is available, since it’s what we’ll use to avoid the need for a full windowing system, which would normally provide us with pixmaps and windows to turn into EGL surfaces.

if (!strstr(extensions, "EGL_KHR_surfaceless_opengl")) {fprintf(stderr, "no surfaceless support, cannot initialize\n");exit(-1);
}

And now we’re finally ready to see what outputs are available for us to use. There are several good references for KMS output handling: the DDX drivers for radeon, nouveau, and intel, and testdisplay.c in the intel-gpu-tools package. (The below is taken from eglkms.c in the mesa-demos package.)

    drmModeRes *resources;drmModeConnector *connector;drmModeEncoder *encoder;int i;/* Find the first available connector with modes */resources = drmModeGetResources(fd);if (!resources) {fprintf(stderr, "drmModeGetResources failed\n");return;}for (i = 0; i < resources->count_connectors; i++) {connector = drmModeGetConnector(fd, resources->connectors[i]);if (connector == NULL)continue;if (connector->connection == DRM_MODE_CONNECTED &&connector->count_modes > 0)break;drmModeFreeConnector(connector);}if (i == resources->count_connectors) {fprintf(stderr, "No currently active connector found.\n");return;}for (i = 0; i < resources->count_encoders; i++) {encoder = drmModeGetEncoder(fd, resources->encoders[i]);if (encoder == NULL)continue;if (encoder->encoder_id == connector->encoder_id)break;drmModeFreeEncoder(encoder);}

At this point we have connector, encoder, and mode structures we’ll use to put something on the display later.

Drawing & displaying

We’ve initialized EGL, but we need to bind an API and create a context. In this case, we’ll use OpenGL.

    EGLContext ctx;eglBindAPI(EGL_OPENGL_API);ctx = eglCreateContext(dpy, NULL, EGL_NO_CONTEXT, NULL);eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, ctx);

Now we have a fully functional KMS and EGL stack and it’s time for a little bit of glue magic. We need to create some buffers using GBM and bind them into EGL images that we can use as renderbuffers.

    EGLImageKHR image;struct gbm_bo *bo;GLuint fb, color_rb, depth_rb;uint32_t handle, stride;/* Create a full screen buffer for use as a render target */bo = gbm_bo_create(gbm, mode.hdisplay, mode.vdisplay, GBM_BO_FORMAT_XRGB888, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);glGenFramebuffers(1, &fb);glBindFramebuffer(GL_FRAMEBUFFER_EXT, fb);handle = gbm_bo_get_handle(bo).u32;stride = gbm_bo_get_pitch(bo);image = eglCreateImageKHR(dpy, NULL, EGL_NATIVE_PIXMAP_KHR, bo, NULL);/* Set up render buffer... */glGenRenderbuffers(1, &color_rb);glBindRenderbuffer(GL_RENDERBUFFER_EXT, color_rb);glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, image);glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, color_rb);/* and depth buffer */glGenRenderbuffers(1, &depth_rb);glBindRenderbuffer(GL_RENDERBUFFER_EXT, depth_rb);glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, mode.hdisplay, mode.vdisplay);glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_rb);if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT)) != GL_FRAMEBUFFER_COMPLETE) {fprintf(stderr, "something bad happened\n");exit(-1);}

At this point, you’re all ready to start rendering using standard GL calls. Note that since we don’t have a window system or a window bound, we won’t be using eglSwapBuffers() to display the final renderbuffer. But we still need to make sure the rendering is finished before we display it, so we can use glFinish() or some out of band synchronization mechanism (TBD) to ensure our rendering is complete before we display the new buffer.

Assuming we have something presentable, we can now try to display it:

    uint32_t crtc;/* Create a KMS framebuffer handle to set a mode with */drmModeAddFB(fd, mode.hdisplay, mode.vdisplay, 24, 32, stride, handle, &fb_id);drmModeSetCrtc(fd, encoder->crtc_id, fb_id, 0, 0, connector->connector_id, 1, mode);

In this example, we’re assuming a 24 bit depth buffer with 32 bits per pixel. That can of course vary, but what’s supported will depend on the chipset (24/32 is fairly common however). The drmModeSetCrtc call will also take care to simply flip to the fb in question if the mode timings are already programmed and are the same as the mode timings passed into the call. This allows for a simple page flipping scheme that simply creates two fbs using AddFB (pointing at different buffers) and flips between them with SetCrtc calls in a loop. Alternately, one can simply draw to the buffer that’s being displayed, if the visibility of partial rendering isn’t a problem.

DRM master privs and authentication

I forgot to mention that any program like this must drop DRM master privileges if another app, like X, wants to start up and use the DRM layer. The calls for this are drmSetMaster(int fd) and drmDropMaster(int fd). If no other DRM master is present, the SetMaster call should succeed. And before switching away due to a dbus call or whatever, any console program using the DRM layer should call drmDropMaster to allow the next client to get access to the DRM. Alternately, the console program could provide a display management API and make X a slave of that interface. That would also mean providing DRM authentication for other apps wanting to do direct rendering (typically master privs are required for display management, and simple auth privs are required to do command submission). Wayland is a good example of a display manager that provides this kind of functionality.

And that’s all there is to it, and should be enough to get someone started on kmscon… :) If you have questions or comments, feel free to bring them up at dri-devel@lists.freedesktop.org, in the comments section here, or via email to me.

• Trackback (0)

EGL Off-Screen rendering using GBM相关推荐

  1. 与context的关系_你还不知道 OpenGL ES 和 EGL 的关系?

    什么是 EGL EGL 是 OpenGL ES 和本地窗口系统(Native Window System)之间的通信接口,它的主要作用: 与设备的原生窗口系统通信: 查询绘图表面的可用类型和配置: 创 ...

  2. Analysis of Cloud Computing Architectures阅读笔记--提出了Screen虚拟化方法

    作者:Ritika Mittal, Kritika Soni 单位:来自印度的一个私立学校,Manav Rachna International University 文章大意: 分析了云计算的一些基 ...

  3. win10 64位下mingw4.9编译qt5.6.2

    目录 一.安装mingw 二.编译qt 1.解压文件 2.安装python 3.configure 4.mingw32-make 5.obj file too big问题的解决 6.单独模块的编译 三 ...

  4. 【chromium】 渲染显示相关概念

    DRM(Direct Rendering Manager) DRM 由两个部分组成:一是 Kernel 的子系统,这个子系统对硬件 GPU 操作进行了一层框架封装.二是提供了一个 libdrm 库,里 ...

  5. 帧缓冲区对象 FBO

    帧缓冲区对象 FBO(Frame Buffer Object). 1.FBO(framebuffer object) (我习惯于把EGL创建的framebuffer称为framebuffer,也叫做w ...

  6. Qt源码编译configure配置参数

    安装选项 选项 作用 -prefix <dir> 指定部署目录(默认 /usr/local/Qt-5.6.0) -extprefix <dir> 安装目录(默认 SYSROOT ...

  7. CEF:给客户端内嵌一个Chrome吧

    原文:http://yogurtcat.com/posts/cef/hello-cef.html 发表于: 2013-03-31 20:20   |  更多相关文章: browser CEF Chro ...

  8. 手机网站开发必修课[1]:手机浏览器 本文来自:http://www.fool2fish.cn/?p=290

    前言: 头大的是,除了自己公司已有的一些经验,网上恐怕没有过多的(公开的)文档可以参考.  09年上半年的工作重心全在手机网页开发上面,这使得自己某种程度上也成了拓荒者.现将这段时间的开发心得同大家分 ...

  9. 用Twebbrowser做可控编辑器与MSHTML

    首先要明白mshtml的属性方法: {IHTMLDocument2 方法:} write //写入 writeln //写入并换行 open //打开一个流,以收集 document.write 或 ...

最新文章

  1. oracle11g dataguard windows,Oracle11g 搭建DataGuard(笔记)
  2. 用Eclipse开发PHP项目
  3. 物流企业计算机运用,计算机物流在企业决策
  4. C# 类(7) 继承
  5. MySQL高级 - 锁 - InnoDB行锁 - 争用情况查看
  6. sklearn——AdaBoost应用
  7. localStorage、sessionStorage详解,以及storage事件使用
  8. 30个python常用代码大全_30 个 Python 常用极简代码,拿走就用
  9. 环境试验的认识和环境可靠性测试
  10. 数据库学习总结(六)——查询练习题(1)
  11. 电子邮箱地址如何注册?个人电子邮箱地址大全
  12. LeetCode 263 Ugly Number(丑数)
  13. raid5是计算机的什么知识,关于raid5的知识
  14. 阿里免费网盘teambition使用初体验
  15. Lesson 43 Smart 组件 vs Dumb 组件
  16. 程序设计入门——C语言 翁恺 第一次单元测试
  17. 黑客入侵微软邮件服务器部署勒索软件、惠普更新打印机漏洞|12月2日全球网络安全热点
  18. C++图书管理查询系统
  19. autojs下载大文件
  20. 关于Macbook Pro/Air 键盘输入乱码,重置NVRAM无效

热门文章

  1. 精品博客推荐:为数不多的维术,高质量文章尽在这里
  2. 东莞理工专插本计算机专业,东莞理工学院专插本介绍
  3. IDEA手动下载MySQL驱动并连接数据库
  4. hyperMILL2018刀具库模板文件
  5. 号称可替代MATLAB的国产软件来了!
  6. 企业级短视频直播带货系统怎么运营,有哪些步骤?
  7. Google Play 开发者播客节目 | 中文专辑 出海同学会 上线!
  8. linux下文件搜索
  9. 深入了解Jit编译发生的过程
  10. DDD 中的几个困难问题