This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

MALI-400 : eglCreateImageKHR, EGL_GL_TEXTURE_2D_KHR and updating textures with the CPU

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

Parents
  • 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;
    }
    
Reply
  • 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;
    }
    
Children