Created
December 4, 2022 01:33
-
-
Save shimomura1004/21762c90bd880eabc3755a067f257469 to your computer and use it in GitHub Desktop.
Use texture on wayland egl
This file contains 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
/* | |
* 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, ®istry_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