Last active
February 21, 2026 11:43
-
-
Save hoshinolina/9d0731cba9fad23562dda90106178cf8 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <assert.h> | |
| #include <drm/drm_fourcc.h> | |
| #include <fcntl.h> | |
| #include <gbm.h> | |
| #include <stdbool.h> | |
| #include <stdio.h> | |
| #include <string.h> | |
| #include <unistd.h> | |
| #define GL_GLEXT_PROTOTYPES | |
| #include <GL/gl.h> | |
| #define EGL_EGLEXT_PROTOTYPES | |
| #include <EGL/egl.h> | |
| #include <EGL/eglext.h> | |
| #include <GLES3/gl31.h> | |
| #include <GLES2/gl2ext.h> | |
| const char *vertexShaderSource = | |
| "#version 310 es\n" | |
| "layout (location = 0) in highp vec3 aPos;\n" | |
| "layout (location = 1) in highp vec2 aTexCoord;\n" | |
| "out highp vec2 TexCoord;\n" | |
| "void main()\n" | |
| "{\n" | |
| " gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n" | |
| " TexCoord = aTexCoord;\n" | |
| "}\0"; | |
| const char *fragmentShaderSource = | |
| "#version 310 es\n" | |
| "#extension GL_OES_EGL_image_external : require\n" | |
| "out highp vec4 FragColor;\n" | |
| "in highp vec2 TexCoord;\n" | |
| "uniform samplerExternalOES ourTexture;\n" | |
| "\n" | |
| "void main()\n" | |
| "{\n" | |
| " FragColor = texture2D(ourTexture, TexCoord);\n" | |
| "}\n"; | |
| void check_egl_error(void) { | |
| GLint eglerror = eglGetError(); | |
| if (eglerror != EGL_SUCCESS) { | |
| fprintf(stderr, "EGL error: %d\n", eglerror); | |
| } | |
| assert(eglerror == EGL_SUCCESS); | |
| } | |
| void check_error(void) { | |
| check_egl_error(); | |
| GLenum error = glGetError(); | |
| if (error != GL_NO_ERROR) { | |
| fprintf(stderr, "GL err: %d\n", error); | |
| } | |
| assert(error == GL_NO_ERROR); | |
| } | |
| int32_t main(int32_t argc, char *argv[]) { | |
| bool res; | |
| assert(argc == 3); | |
| const char *src_device = argv[1]; | |
| const char *dst_device = argv[2]; | |
| int src_fd = open(src_device, O_RDWR); | |
| assert(src_fd > 0); | |
| struct gbm_device *src_gbm = gbm_create_device(src_fd); | |
| assert(src_gbm != NULL); | |
| printf("Source device backend: %s\n", gbm_device_get_backend_name(src_gbm)); | |
| int dst_fd = open(dst_device, O_RDWR); | |
| assert(dst_fd > 0); | |
| struct gbm_device *dst_gbm = gbm_create_device(dst_fd); | |
| assert(dst_gbm != NULL); | |
| printf("Dest device backend: %s\n", gbm_device_get_backend_name(dst_gbm)); | |
| struct gbm_bo *bo = NULL; | |
| uint64_t mod = DRM_FORMAT_MOD_LINEAR; | |
| bo = gbm_bo_create_with_modifiers2(src_gbm, 512, 512, GBM_FORMAT_ARGB8888, | |
| &mod, 1, 0); | |
| assert(bo); | |
| EGLDisplay egl_dpy = | |
| eglGetPlatformDisplay(EGL_PLATFORM_GBM_MESA, dst_gbm, NULL); | |
| assert(egl_dpy != NULL); | |
| res = eglInitialize(egl_dpy, NULL, NULL); | |
| assert(res); | |
| printf("EGL vendor: %s\n", eglQueryString(egl_dpy, EGL_VENDOR)); | |
| const char *egl_extension_st = eglQueryString(egl_dpy, EGL_EXTENSIONS); | |
| assert(strstr(egl_extension_st, "EGL_KHR_create_context") != NULL); | |
| // clang-format off | |
| static const EGLint config_attribs[] = { | |
| EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR, | |
| EGL_NONE, | |
| }; | |
| // clang-format on | |
| EGLConfig cfg; | |
| EGLint count; | |
| res = eglChooseConfig(egl_dpy, config_attribs, &cfg, 1, &count); | |
| assert(res); | |
| res = eglBindAPI(EGL_OPENGL_ES_API); | |
| assert(res); | |
| static const EGLint attribs[] = {EGL_CONTEXT_MAJOR_VERSION, 3, EGL_NONE}; | |
| EGLContext core_ctx = eglCreateContext(egl_dpy, cfg, EGL_NO_CONTEXT, attribs); | |
| assert(core_ctx != EGL_NO_CONTEXT); | |
| res = eglMakeCurrent(egl_dpy, NULL, NULL, core_ctx); | |
| assert(res); | |
| // clang-format off | |
| EGLAttrib attribute_list[] = { | |
| EGL_WIDTH, gbm_bo_get_width(bo), | |
| EGL_HEIGHT, gbm_bo_get_height(bo), | |
| EGL_LINUX_DRM_FOURCC_EXT, gbm_bo_get_format(bo), | |
| EGL_DMA_BUF_PLANE0_FD_EXT, gbm_bo_get_fd(bo), | |
| EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0, | |
| EGL_DMA_BUF_PLANE0_PITCH_EXT, gbm_bo_get_stride_for_plane(bo, 0), | |
| EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, (uint32_t)mod, | |
| EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT, (uint32_t)(mod >> 32), | |
| EGL_NONE, | |
| }; | |
| // clang-format on | |
| EGLImage image = eglCreateImage(egl_dpy, EGL_NO_CONTEXT, | |
| EGL_LINUX_DMA_BUF_EXT, 0, attribute_list); | |
| assert(image != EGL_NO_IMAGE); | |
| check_egl_error(); | |
| GLuint fbo_tex; | |
| glGenTextures(1, &fbo_tex); | |
| glBindTexture(GL_TEXTURE_2D, fbo_tex); | |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 512, 512, 0, GL_RGB, GL_UNSIGNED_BYTE, | |
| NULL); | |
| unsigned int fbo; | |
| glGenFramebuffers(1, &fbo); | |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); | |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, | |
| fbo_tex, 0); | |
| GLuint color_tex; | |
| glGenTextures(1, &color_tex); | |
| glBindTexture(GL_TEXTURE_EXTERNAL_OES, color_tex); | |
| glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, image); | |
| check_error(); | |
| glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
| glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
| check_error(); | |
| unsigned int vertexShader; | |
| vertexShader = glCreateShader(GL_VERTEX_SHADER); | |
| glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); | |
| glCompileShader(vertexShader); | |
| unsigned int fragmentShader; | |
| fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); | |
| glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); | |
| glCompileShader(fragmentShader); | |
| unsigned int shaderProgram; | |
| shaderProgram = glCreateProgram(); | |
| glAttachShader(shaderProgram, vertexShader); | |
| glAttachShader(shaderProgram, fragmentShader); | |
| glLinkProgram(shaderProgram); | |
| glUseProgram(shaderProgram); | |
| check_error(); | |
| float vertices[] = { | |
| // positions // texture coords | |
| 0.5f, 0.5f, 0.0f, 1.0f, 1.0f, // top right | |
| 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, // bottom right | |
| -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, // bottom left | |
| -0.5f, 0.5f, 0.0f, 0.0f, 1.0f // top left | |
| }; | |
| unsigned int VBO; | |
| glGenBuffers(1, &VBO); | |
| glBindBuffer(GL_ARRAY_BUFFER, VBO); | |
| glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); | |
| glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), | |
| (void *)(3 * sizeof(float))); | |
| glEnableVertexAttribArray(2); | |
| printf("Draw...\n"); | |
| glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | |
| glFlush(); | |
| glFinish(); | |
| check_error(); | |
| printf("Draw done...\n"); | |
| eglDestroyContext(egl_dpy, core_ctx); | |
| gbm_device_destroy(dst_gbm); | |
| gbm_device_destroy(src_gbm); | |
| close(src_fd); | |
| close(dst_fd); | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment