Skip to content

Instantly share code, notes, and snippets.

@hoshinolina
Last active February 21, 2026 11:43
Show Gist options
  • Select an option

  • Save hoshinolina/9d0731cba9fad23562dda90106178cf8 to your computer and use it in GitHub Desktop.

Select an option

Save hoshinolina/9d0731cba9fad23562dda90106178cf8 to your computer and use it in GitHub Desktop.
#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