Skip to content

Instantly share code, notes, and snippets.

@shimomura1004
Created December 4, 2022 01:33
Show Gist options
  • Save shimomura1004/21762c90bd880eabc3755a067f257469 to your computer and use it in GitHub Desktop.
Save shimomura1004/21762c90bd880eabc3755a067f257469 to your computer and use it in GitHub Desktop.
Use texture on wayland egl
/*
* A simple Wayland EGL program to show a triangle
*
* cc -o triangle_simple triangle_simple.c -lwayland-client -lwayland-egl -lEGL -lGLESv2
*/
#include <EGL/egl.h>
#include <GLES2/gl2.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <wayland-client.h>
#include <wayland-egl.h>
GLuint textureId;
GLint samplerLoc;
GLint positionLoc;
GLint texCoordLoc;
struct WaylandGlobals
{
struct wl_compositor *compositor;
struct wl_shell *shell;
};
/*
* Registry callbacks
*/
static void registry_global(void *data, struct wl_registry *registry, uint32_t id, const char *interface, uint32_t version)
{
struct WaylandGlobals *globals = (struct WaylandGlobals *)data;
if (strcmp(interface, "wl_compositor") == 0)
{
globals->compositor = wl_registry_bind(registry, id, &wl_compositor_interface, 1);
}
else if (strcmp(interface, "wl_shell") == 0)
{
globals->shell = wl_registry_bind(registry, id, &wl_shell_interface, 1);
}
}
static const struct wl_registry_listener registry_listener = {registry_global, NULL};
/*
* Connect to the Wayland display and return the display and the surface
* output wlDisplay
* output wlSurface
*/
static void initWaylandDisplay(struct wl_display **wlDisplay, struct wl_surface **wlSurface)
{
struct WaylandGlobals globals = {0};
*wlDisplay = wl_display_connect(NULL);
assert(*wlDisplay != NULL);
struct wl_registry *registry = wl_display_get_registry(*wlDisplay);
wl_registry_add_listener(registry, &registry_listener, (void *)&globals);
wl_display_dispatch(*wlDisplay);
wl_display_roundtrip(*wlDisplay);
assert(globals.compositor);
assert(globals.shell);
*wlSurface = wl_compositor_create_surface(globals.compositor);
assert(*wlSurface != NULL);
struct wl_shell_surface *shellSurface = wl_shell_get_shell_surface(globals.shell, *wlSurface);
wl_shell_surface_set_toplevel(shellSurface);
}
/*
* Configure EGL and return necessary resources
* input nativeDisplay
* input nativeWindow
* output eglDisplay
* output eglSurface
*/
static void initEGLDisplay(EGLNativeDisplayType nativeDisplay, EGLNativeWindowType nativeWindow, EGLDisplay *eglDisplay, EGLSurface *eglSurface)
{
EGLint number_of_config;
EGLint config_attribs[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_NONE};
static const EGLint context_attribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE};
*eglDisplay = eglGetDisplay(nativeDisplay);
assert(*eglDisplay != EGL_NO_DISPLAY);
EGLBoolean initialized = eglInitialize(*eglDisplay, NULL, NULL);
assert(initialized == EGL_TRUE);
EGLConfig configs[1];
eglChooseConfig(*eglDisplay, config_attribs, configs, 1, &number_of_config);
assert(number_of_config);
EGLContext eglContext = eglCreateContext(*eglDisplay, configs[0], EGL_NO_CONTEXT, context_attribs);
*eglSurface = eglCreateWindowSurface(*eglDisplay, configs[0], nativeWindow, NULL);
assert(*eglSurface != EGL_NO_SURFACE);
EGLBoolean makeCurrent = eglMakeCurrent(*eglDisplay, *eglSurface, *eglSurface, eglContext);
assert(makeCurrent == EGL_TRUE);
}
/*
* Connect Wayland and make EGL
* input width
* input height
* output wlDisplay
* output eglDisplay
* output eglSurface
*/
static void initWindow(GLint width, GLint height, struct wl_display **wlDisplay, EGLDisplay *eglDisplay, EGLSurface *eglSurface)
{
struct wl_surface *wlSurface;
initWaylandDisplay(wlDisplay, &wlSurface);
struct wl_egl_window *wlEglWindow = wl_egl_window_create(wlSurface, width, height);
assert(wlEglWindow != NULL);
initEGLDisplay((EGLNativeDisplayType)*wlDisplay, (EGLNativeWindowType)wlEglWindow, eglDisplay, eglSurface);
}
/*
* Return the loaded and compiled shader
*/
GLuint LoadShader(GLenum type, const char *shaderSrc)
{
GLuint shader = glCreateShader(type);
assert(shader);
glShaderSource(shader, 1, &shaderSrc, NULL);
glCompileShader(shader);
GLint compiled;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
assert(compiled);
return shader;
}
void UpdateTexture(GLubyte *pixels_, int i)
{
printf("i=%d\n", i);
GLubyte pixels[4 * 3] = {
i, 0, 0, // Green
i, 0, 0, // Red
i, 0, 0, // Blue
255, 255, 0 // Yellow
};
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureId);
glTexSubImage2D(
GL_TEXTURE_2D,
0,
1920 / 2,
1020 / 2,
1920 / 2,
1020 / 2,
GL_RGB,
GL_UNSIGNED_BYTE,
pixels
);
}
GLuint CreateSimpleTexture2D()
{
// Texture object handle
GLuint textureId;
// todo: change here to rgb data from camera
// 2x2 Image, 3 bytes per pixel (R, G, B)
GLubyte pixels[4 * 3] = {
255, 0, 0, // Red
0, 255, 0, // Green
0, 0, 255, // Blue
255, 255, 0 // Yellow
};
// Use tightly packed data
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// Generate a texture object
glGenTextures(1, &textureId);
// Bind the texture object
glBindTexture(GL_TEXTURE_2D, textureId);
// Load the texture
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
// Set the filtering mode
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
return textureId;
}
/*
* Initialize the shaders and return the program object
*/
GLuint initProgramObject()
{
char vShaderStr[] =
"attribute vec4 a_position; \n"
"attribute vec2 a_texCoord; \n"
"varying vec2 v_texCoord; \n"
"void main() \n"
"{ \n"
" gl_Position = a_position; \n"
" v_texCoord = a_texCoord; \n"
"} \n";
char fShaderStr[] =
"precision mediump float; \n"
"varying vec2 v_texCoord; \n"
"uniform sampler2D s_texture; \n"
"void main() \n"
"{ \n"
" gl_FragColor = texture2D( s_texture, v_texCoord );\n"
"} \n";
// バーテックスシェーダとフラグメントシェーダのソースコードをロード
GLuint vertexShader = LoadShader(GL_VERTEX_SHADER, vShaderStr);
GLuint fragmentShader = LoadShader(GL_FRAGMENT_SHADER, fShaderStr);
// シェーダプログラムを作成
GLuint programObject = glCreateProgram();
assert(programObject);
// プログラムにシェーダを登録
glAttachShader(programObject, vertexShader);
glAttachShader(programObject, fragmentShader);
// コンパイル
glLinkProgram(programObject);
// attribute location を取得
positionLoc = glGetAttribLocation(programObject, "a_position");
texCoordLoc = glGetAttribLocation(programObject, "a_texCoord");
// テクスチャの sampler location を取得
samplerLoc = glGetUniformLocation(programObject, "s_texture");
// テクスチャをロード
textureId = CreateSimpleTexture2D();
GLint linked;
glGetProgramiv(programObject, GL_LINK_STATUS, &linked);
assert(linked);
return programObject;
}
void draw(GLuint programObject, GLint width, GLint height)
{
GLfloat vVertices[] = {
-1.0f, 1.0f, 0.0f, // Position 0
0.0f, 0.0f, // TexCoord 0
-1.0f, -1.0f, 0.0f, // Position 1
0.0f, 1.0f, // TexCoord 1
1.0f, -1.0f, 0.0f, // Position 2
1.0f, 1.0f, // TexCoord 2
1.0f, 1.0f, 0.0f, // Position 3
1.0f, 0.0f // TexCoord 3
};
GLushort indices[] =
{0, 1, 2, 0, 2, 3};
// Set the viewport
glViewport(0, 0, width, height);
// Clear the color buffer
glClear(GL_COLOR_BUFFER_BIT);
// Use the program object
glUseProgram(programObject);
// Load the vertex position
glVertexAttribPointer(positionLoc, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), vVertices);
// Load the texture coordinate
glVertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), &vVertices[3]);
glEnableVertexAttribArray(positionLoc);
glEnableVertexAttribArray(texCoordLoc);
// Bind the texture
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureId);
// Set the sampler texture unit to 0
glUniform1i(samplerLoc, 0);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
}
int main(int argc, char **argv)
{
int width = 1920;
int height = 1020;
struct wl_display *wlDisplay;
EGLDisplay eglDisplay;
EGLSurface eglSurface;
initWindow(width, height, &wlDisplay, &eglDisplay, &eglSurface);
GLuint programObject = initProgramObject();
assert(programObject);
draw(programObject, width, height);
eglSwapBuffers(eglDisplay, eglSurface);
//int i=0;
while (wl_display_dispatch(wlDisplay) != -1)
{
// UpdateTexture(NULL, i);
// i = (i + 1) % 255;
// eglSwapBuffers(eglDisplay, eglSurface);
}
glDeleteProgram(programObject);
wl_display_disconnect(wlDisplay);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment