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.
View all questions in Graphics and Gaming forum