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; }
It's a bit crazy that nobody ever does this kind on thing on Linux.
Well, I'll just give up and revert to the slow as hell gxTexImage2D.
(and thanks for at least trying, Wasim ! Cheers)
Apologies for late reply. I have been away for the last 2 weeks. I a still looking at this I need some help from our driver engineers. As soon as I hear back I will update you.
Hi Tramboi,
I am Wasim's colleague from driver team. I saw you mentioned it doesn't work when using eglLockSurfaceKHR. Do you mean there is an EGL error reported?
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 ?