Hello everybody, I'm currently struggling with the said system.Is there somewhere a *full* sample code for Linux that does create an EGLImage for a texture and demonstrates how to update it with the CPU ?
Reference documentation seems ok but eglGetError keeps telling me I don't know what I'm doing
I won't post my various tries here because they don't work and therefore have no value for the reader, but I've been romaing the web and trying stuff for a while.
Cheers, Tramb
Here is the kind of boilerplate code that I'd like to work, by joining lots of disparateinformation from the web.
Except lock/unlocking fails.
#include <cassert> #include <cinttypes> #include <cstdint> #include <cstdio> #include <cstdlib> #include <cstring> #include <ctime> #define EGL_EGLEXT_PROTOTYPES #include <EGL/egl.h> #include <EGL/eglext.h> #define GL_GLEXT_PROTOTYPES #include <GLES2/gl2.h> #include <GLES2/gl2ext.h> #include <linux/fb.h> #include <sys/ioctl.h> #include <unistd.h> struct fbdev_window nativeWindow = { .width = 1280, .height = 720, }; int main(int argc, char* argv []) { auto display = eglGetDisplay(EGL_DEFAULT_DISPLAY); assert(display != EGL_NO_DISPLAY); { EGLint major = 0; EGLint minor = 0; auto success = eglInitialize(display, &major, &minor); assert(success); printf("EGL Initialize: %d.%d\n", major, minor); } printf("EGL Version: \"%s\"\n", eglQueryString(display, EGL_VERSION)); printf("EGL Vendor: \"%s\"\n", eglQueryString(display, EGL_VENDOR)); printf("EGL Extensions: \"%s\"\n", eglQueryString(display, EGL_EXTENSIONS)); EGLConfig config = {}; { EGLint configCount = 0; EGLint configAttributes [] = { EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_BUFFER_SIZE, 32, EGL_STENCIL_SIZE, 0, EGL_DEPTH_SIZE, 0, EGL_SAMPLES, 4, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PIXMAP_BIT, EGL_NONE }; eglChooseConfig(display, configAttributes, &config, 1, &configCount); } static EGLint const contextAttributes [] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; auto context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttributes); assert(context != EGL_NO_CONTEXT); static EGLint const windowAttributes [] = {EGL_NONE}; auto surface = eglCreateWindowSurface(display, config, &nativeWindow, windowAttributes); assert(surface != EGL_NO_SURFACE); GLint width = 0; { auto success = eglQuerySurface(display, surface, EGL_WIDTH, &width); assert(success); } GLint height = 0; { auto success = eglQuerySurface(display, surface, EGL_HEIGHT, &height); assert(success); } printf("Surface size: %dx%d\n", width, height); { auto success = eglMakeCurrent(display, surface, surface, context); assert(success); } printf("GL Vendor: \"%s\"\n", glGetString(GL_VENDOR)); printf("GL Renderer: \"%s\"\n", glGetString(GL_RENDERER)); printf("GL Version: \"%s\"\n", glGetString(GL_VERSION)); printf("GL Extensions: \"%s\"\n", glGetString(GL_EXTENSIONS)); auto vertShader = glCreateShader(GL_VERTEX_SHADER); assert(vertShader); static char const* vertShaderSource = "attribute vec4 aPosition; \n" "attribute vec4 aColor; \n" " \n" "varying vec4 vColor; \n" " \n" "void main() \n" "{ \n" " vColor = aColor; \n" " gl_Position = aPosition; \n" "} \n"; glShaderSource(vertShader, 1, &vertShaderSource, NULL); glCompileShader(vertShader); { GLint status = GL_FALSE; glGetShaderiv(vertShader, GL_COMPILE_STATUS, &status); { GLint length = 0; glGetShaderiv(vertShader, GL_INFO_LOG_LENGTH, &length); if (length > 0) { auto logBuffer = new char[length]; memset(logBuffer, 0, length); glGetShaderInfoLog(vertShader, length, NULL, logBuffer); printf("Vertex shader log:\n%s\n", logBuffer); delete [] logBuffer; } assert(status == GL_TRUE); } } auto fragShader = glCreateShader(GL_FRAGMENT_SHADER); assert(fragShader); static char const* fragShaderSource = #ifndef NOEGLIMAGE "#extension GL_OES_EGL_image_external : require\n" #endif "precision mediump float; \n" " \n" "varying vec4 vColor; \n" #ifdef NOEGLIMAGE "uniform sampler2D uTexture; \n" #else "uniform samplerExternalOES uTexture; \n" #endif "uniform float uWidth; \n" "uniform float uHeight; \n" " \n" "void main() \n" "{ \n" " vec2 coord = gl_FragCoord.xy;\n" " coord.x /= uWidth;\n" " coord.y /= uHeight;\n" " gl_FragColor = texture2D(uTexture, coord); \n" "} \n"; glShaderSource(fragShader, 1, &fragShaderSource, NULL); glCompileShader(fragShader); { GLint status = GL_FALSE; glGetShaderiv(fragShader, GL_COMPILE_STATUS, &status); { GLint length = 0; glGetShaderiv(fragShader, GL_INFO_LOG_LENGTH, &length); if (length > 0) { auto logBuffer = new char[length]; memset(logBuffer, 0, length); glGetShaderInfoLog(fragShader, length, NULL, logBuffer); printf("Fragment shader log:\n%s\n", logBuffer); delete [] logBuffer; } assert(status == GL_TRUE); } } auto program = glCreateProgram(); assert(program); glAttachShader(program, vertShader); glAttachShader(program, fragShader); glBindAttribLocation(program, 0, "aPosition"); glBindAttribLocation(program, 1, "aColor"); glLinkProgram(program); { GLint status = GL_FALSE; glGetProgramiv(program, GL_LINK_STATUS, &status); { GLint length = 0; glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length); if (length > 0) { auto logBuffer = new char[length]; memset(logBuffer, 0, length); glGetShaderInfoLog(program, length, NULL, logBuffer); printf("Program log:\n%s\n", logBuffer); delete [] logBuffer; } assert(status == GL_TRUE); } } glUseProgram(program); assert(glGetError() == GL_NO_ERROR); glClearColor(0.2, 0.2, 0.2, 1.0); assert(glGetError() == GL_NO_ERROR); static GLfloat const aPositions [] = { -0.8f, -0.8f, 0.0f, 1.0f, 0.0f, 0.8f, 0.0f, 1.0f, 0.8f, -0.8f, 0.0f, 1.0f }; glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, aPositions); glEnableVertexAttribArray(0); assert(glGetError() == GL_NO_ERROR); static GLfloat const aColors [] = { 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f }; glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, aColors); glEnableVertexAttribArray(1); assert(glGetError() == GL_NO_ERROR); GLuint texture = 0; glGenTextures(1, &texture); glActiveTexture(GL_TEXTURE0); assert(glGetError() == GL_NO_ERROR); glUniform1i(glGetUniformLocation(program, "uTexture"), 0); glUniform1f(glGetUniformLocation(program, "uWidth"), width); glUniform1f(glGetUniformLocation(program, "uHeight"), height); assert(glGetError() == GL_NO_ERROR); static uint8_t textureData[4 * 4][4] = { {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x7f, 0xff}, {0x00, 0x7f, 0x00, 0xff}, {0x00, 0x7f, 0x7f, 0xff}, {0x00, 0xff, 0x00, 0xff}, {0x00, 0xff, 0x7f, 0xff}, {0x7f, 0x00, 0x00, 0xff}, {0x7f, 0x00, 0x7f, 0xff}, {0x7f, 0x7f, 0x00, 0xff}, {0x7f, 0x7f, 0x7f, 0xff}, {0x7f, 0xff, 0x00, 0xff}, {0x7f, 0xff, 0x7f, 0xff}, {0xff, 0x00, 0x00, 0xff}, {0xff, 0x00, 0x7f, 0xff}, {0xff, 0x7f, 0x00, 0xff}, {0xff, 0x7f, 0x7f, 0xff}, }; fbdev_pixmap pixmap = {}; pixmap.height = 4; pixmap.width = 4; pixmap.bytes_per_pixel = 4; pixmap.buffer_size = 32; pixmap.red_size = 8; pixmap.green_size = 8; pixmap.blue_size = 8; pixmap.alpha_size = 8; pixmap.luminance_size = 0; pixmap.flags = static_cast<fbdev_pixmap_flags>(FBDEV_PIXMAP_DEFAULT) /* | FBDEV_PIXMAP_EGL_MEMORY | FBDEV_PIXMAP_SUPPORTS_UMP | FBDEV_PIXMAP_ALPHA_FORMAT_PRE | FBDEV_PIXMAP_COLORSPACE_sRGB | FBDEV_PIXMAP_DMA_BUF */; pixmap.data = reinterpret_cast<unsigned short*>(textureData); pixmap.format = 0; EGLint const imageAttributes [] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE }; auto image = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, reinterpret_cast<EGLClientBuffer>(&pixmap), imageAttributes); assert(eglGetError() == EGL_SUCCESS); glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture); glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, image); glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST); assert(glGetError() == GL_NO_ERROR); // Doesn't work /* EGLint bitmapAdress, bitmapPitch; eglQuerySurface(display, image, EGL_BITMAP_POINTER_KHR, &bitmapAdress); assert(eglGetError() == EGL_SUCCESS); eglQuerySurface(display, image, EGL_BITMAP_PITCH_KHR, &bitmapPitch); assert(eglGetError() == EGL_SUCCESS); printf("Address: %x\nPitch %d\n", bitmapAdress, bitmapPitch); */ eglSwapInterval(display, 1); glViewport(0, 0, width, height); assert(glGetError() == GL_NO_ERROR); while (1) { glClear(GL_COLOR_BUFFER_BIT); glDrawArrays(GL_TRIANGLES, 0, 3); assert(glGetError() == GL_NO_ERROR); eglSwapBuffers(display, surface); assert(eglGetError() == EGL_SUCCESS); EGLint lockAttribList[] = { EGL_LOCK_USAGE_HINT_KHR, EGL_WRITE_SURFACE_BIT_KHR, EGL_NONE }; // Doesn't work EGLBoolean lockResult = eglLockSurfaceKHR(display, image, lockAttribList); assert(eglGetError() == EGL_SUCCESS); assert(lockResult); // update the texture data for (auto i = 0; i < 4; ++i) { for (auto x = 0; x < 4; ++x) { for (auto y = 0; y < 4; ++y) { textureData[4 * x + y][i]++; } } } EGLBoolean unlockResult = eglUnlockSurfaceKHR(display, image); assert(eglGetError() == EGL_SUCCESS); assert(unlockResult); assert(glGetError() == GL_NO_ERROR); glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0); glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture); assert(glGetError() == GL_NO_ERROR); assert(eglGetError() == EGL_SUCCESS); //glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, 0); assert(glGetError() == GL_NO_ERROR); assert(eglGetError() == EGL_SUCCESS); glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, image); assert(glGetError() == GL_NO_ERROR); assert(eglGetError() == EGL_SUCCESS); } eglDestroyImageKHR(display, image); return 0; }
Bertrand Augereau were you able to do zero-copy upload of image data to OpenGL ES ? currently I am stuck in the same issue. I am reading data from camera and using glTexImage2D to upload to mali400 gpu. but it is very slow. Is there working sample code that does zero copy with eglCreateImageKHR OR EXT_image_dma_buf_import OR EGL_GL_TEXTURE_2D_KHR OR Pixmap ?
View all questions in Graphics and Gaming forum