Esempio n. 1
0
/* Draw one video frame onto EGL surface.
 * @param vt           vidtex instance.
 * @param video_frame  MMAL opaque buffer handle for decoded video frame. Can't be NULL.
 */
static void vidtex_draw(VIDTEX_T *vt, void *video_frame)
{
   EGLImageKHR image;
   VIDTEX_IMAGE_SLOT_T *slot;
   static uint32_t frame_num = 0;

   vcos_assert(video_frame);

   glClearColor(0, 0, 0, 0);
   glClearDepthf(1);
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   glLoadIdentity();

   glBindTexture(GL_TEXTURE_EXTERNAL_OES, vt->texture);
   VIDTEX_CHECK_GL(vt);

   /* Lookup or create EGL image corresponding to supplied buffer handle.
    * N.B. Slot array is filled in sequentially, with the images all destroyed together on
    *      vidtex termination; it never has holes. */
   image = EGL_NO_IMAGE_KHR;

   for (slot = vt->slots; slot < vt->slots + vcos_countof(vt->slots); slot++)
   {
      if (slot->video_frame == video_frame)
      {
         vcos_assert(slot->image);
         image = slot->image;
         break;
      }

      if (slot->video_frame == NULL)
      {
         EGLenum target;
         vcos_assert(slot->image == NULL);

         if (vt->opts & VIDTEX_OPT_Y_TEXTURE)
            target = EGL_IMAGE_BRCM_MULTIMEDIA_Y;
         else if (vt->opts & VIDTEX_OPT_U_TEXTURE)
            target = EGL_IMAGE_BRCM_MULTIMEDIA_U;
         else if (vt->opts & VIDTEX_OPT_V_TEXTURE)
            target = EGL_IMAGE_BRCM_MULTIMEDIA_V;
         else
            target = EGL_IMAGE_BRCM_MULTIMEDIA;

         image = eglCreateImageKHR(vt->display, EGL_NO_CONTEXT, target,
               (EGLClientBuffer)video_frame, NULL);
         if (image == EGL_NO_IMAGE_KHR)
         {
            vcos_log_error("EGL image conversion error");
         }
         else
         {
            vcos_log_trace("Created EGL image %p for buf %p", image, video_frame);
            slot->video_frame = video_frame;
            slot->image = image;
         }
         VIDTEX_CHECK_GL(vt);

         break;
      }
   }

   if (slot == vt->slots + vcos_countof(vt->slots))
   {
      vcos_log_error("Exceeded configured max number of EGL images");
   }

   /* Draw the EGL image */
   if (image != EGL_NO_IMAGE_KHR)
   {
      /* Assume 30fps */
      int frames_per_rev = 30 * 15;
      GLfloat angle = (frame_num * 360) / (GLfloat) frames_per_rev;
      frame_num = (frame_num + 1) % frames_per_rev;

      glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, image);
      VIDTEX_CHECK_GL(vt);

      glRotatef(angle, 0.0, 0.0, 1.0);
      glEnableClientState(GL_VERTEX_ARRAY);
      glVertexPointer(3, GL_FLOAT, 0, vt_vertices);
      glDisableClientState(GL_COLOR_ARRAY);
      glEnableClientState(GL_TEXTURE_COORD_ARRAY);
      glTexCoordPointer(2, GL_FLOAT, 0, vt_tex_coords);

      glDrawArrays(GL_TRIANGLES, 0, vcos_countof(vt_tex_coords) / 2);

      eglSwapBuffers(vt->display, vt->surface);

      if (vt->opts & VIDTEX_OPT_IMG_PER_FRAME)
      {
         vidtex_destroy_images(vt);
      }

      vt->num_swaps++;
   }

   VIDTEX_CHECK_GL(vt);
}
Esempio n. 2
0
int
glamor_egl_dri3_fd_name_from_tex(ScreenPtr screen,
                                 PixmapPtr pixmap,
                                 unsigned int tex,
                                 Bool want_name, CARD16 *stride, CARD32 *size)
{
#ifdef GLAMOR_HAS_GBM
    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
    struct glamor_screen_private *glamor_priv =
        glamor_get_screen_private(screen);
    struct glamor_egl_screen_private *glamor_egl;
    EGLImageKHR image;
    struct gbm_bo *bo;
    int fd = -1;

    EGLint attribs[] = {
        EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
        EGL_GL_TEXTURE_LEVEL_KHR, 0,
        EGL_NONE
    };

    glamor_egl = glamor_egl_get_screen_private(scrn);

    glamor_get_context(glamor_priv);

    image = dixLookupPrivate(&pixmap->devPrivates,
                             glamor_egl_pixmap_private_key);

    if (image == EGL_NO_IMAGE_KHR || image == NULL) {
        image = eglCreateImageKHR(glamor_egl->display,
                                  glamor_egl->context,
                                  EGL_GL_TEXTURE_2D_KHR,
                                  (EGLClientBuffer) (uintptr_t)
                                  tex, attribs);
        if (image == EGL_NO_IMAGE_KHR)
            goto failure;

        dixSetPrivate(&pixmap->devPrivates,
                      glamor_egl_pixmap_private_key, image);
        glamor_set_pixmap_type(pixmap, GLAMOR_TEXTURE_DRM);
    }

    bo = gbm_bo_import(glamor_egl->gbm, GBM_BO_IMPORT_EGL_IMAGE, image, 0);
    if (!bo)
        goto failure;

    pixmap->devKind = gbm_bo_get_stride(bo);

    if (want_name) {
        if (glamor_egl->has_gem)
            glamor_get_name_from_bo(glamor_egl->fd, bo, &fd);
    }
    else {
        if (glamor_get_fd_from_bo(glamor_egl->fd, bo, &fd)) {
            *stride = pixmap->devKind;
            *size = pixmap->devKind * gbm_bo_get_height(bo);
        }
    }

    gbm_bo_destroy(bo);
 failure:
    glamor_put_context(glamor_priv);
    return fd;
#else
    return -1;
#endif
}
Esempio n. 3
0
PixmapPtr
glamor_egl_dri3_pixmap_from_fd(ScreenPtr screen,
                               int fd,
                               CARD16 width,
                               CARD16 height,
                               CARD16 stride, CARD8 depth, CARD8 bpp)
{
#ifdef GLAMOR_HAS_GBM
    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
    struct glamor_egl_screen_private *glamor_egl;
    struct gbm_bo *bo;
    EGLImageKHR image;
    PixmapPtr pixmap;
    Bool ret = FALSE;

    EGLint attribs[] = {
        EGL_WIDTH, 0,
        EGL_HEIGHT, 0,
        EGL_LINUX_DRM_FOURCC_EXT, DRM_FORMAT_ARGB8888,
        EGL_DMA_BUF_PLANE0_FD_EXT, 0,
        EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0,
        EGL_DMA_BUF_PLANE0_PITCH_EXT, 0,
        EGL_NONE
    };

    glamor_egl = glamor_egl_get_screen_private(scrn);

    if (!glamor_egl->dri3_capable)
        return NULL;

    if (bpp != 32 || !(depth == 24 || depth == 32) || width == 0 || height == 0)
        return NULL;

    attribs[1] = width;
    attribs[3] = height;
    attribs[7] = fd;
    attribs[11] = stride;
    image = eglCreateImageKHR(glamor_egl->display,
                              EGL_NO_CONTEXT,
                              EGL_LINUX_DMA_BUF_EXT,
                              NULL, attribs);

    if (image == EGL_NO_IMAGE_KHR)
        return NULL;

    /* EGL_EXT_image_dma_buf_import can impose restrictions on the
     * usage of the image. Use gbm_bo to bypass the limitations. */

    bo = gbm_bo_import(glamor_egl->gbm, GBM_BO_IMPORT_EGL_IMAGE, image, 0);
    eglDestroyImageKHR(glamor_egl->display, image);

    if (!bo)
        return NULL;

    pixmap = screen->CreatePixmap(screen, 0, 0, depth, 0);
    screen->ModifyPixmapHeader(pixmap, width, height, 0, 0, stride, NULL);

    ret = glamor_egl_create_textured_pixmap_from_gbm_bo(pixmap, bo);
    gbm_bo_destroy(bo);

    if (ret)
        return pixmap;
    else {
        screen->DestroyPixmap(pixmap);
        return NULL;
    }
#else
    return NULL;
#endif
}
GstBuffer *
gst_egl_image_allocator_alloc_eglimage (GstAllocator * allocator,
    GstEGLDisplay * display, EGLContext eglcontext, GstVideoFormat format,
    gint width, gint height)
{
  GstEGLGLESImageData *data = NULL;
  GstBuffer *buffer;
  GstVideoInfo info;
  gint i;
  gint stride[3];
  gsize offset[3];
  GstMemory *mem[3] = { NULL, NULL, NULL };
  guint n_mem;
  GstMemoryFlags flags = 0;

  memset (stride, 0, sizeof (stride));
  memset (offset, 0, sizeof (offset));

  if (!gst_egl_image_memory_is_mappable ())
    flags |= GST_MEMORY_FLAG_NOT_MAPPABLE;
  /* See https://bugzilla.gnome.org/show_bug.cgi?id=695203 */
  flags |= GST_MEMORY_FLAG_NO_SHARE;

  gst_video_info_set_format (&info, format, width, height);

  switch (format) {
    case GST_VIDEO_FORMAT_RGB:
    case GST_VIDEO_FORMAT_BGR:{
      gsize size;
      EGLImageKHR image;

      mem[0] =
          gst_egl_image_allocator_alloc (allocator, display,
          GST_VIDEO_GL_TEXTURE_TYPE_RGB, GST_VIDEO_INFO_WIDTH (&info),
          GST_VIDEO_INFO_HEIGHT (&info), &size);
      if (mem[0]) {
        stride[0] = size / GST_VIDEO_INFO_HEIGHT (&info);
        n_mem = 1;
        GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE);
      } else {
        data = g_slice_new0 (GstEGLGLESImageData);

        stride[0] = GST_ROUND_UP_4 (GST_VIDEO_INFO_WIDTH (&info) * 3);
        size = stride[0] * GST_VIDEO_INFO_HEIGHT (&info);

        glGenTextures (1, &data->texture);
        if (got_gl_error ("glGenTextures"))
          goto mem_error;

        glBindTexture (GL_TEXTURE_2D, data->texture);
        if (got_gl_error ("glBindTexture"))
          goto mem_error;

        /* Set 2D resizing params */
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        /* If these are not set the texture image unit will return
         * * (R, G, B, A) = black on glTexImage2D for non-POT width/height
         * * frames. For a deeper explanation take a look at the OpenGL ES
         * * documentation for glTexParameter */
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        if (got_gl_error ("glTexParameteri"))
          goto mem_error;

        glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB,
            GST_VIDEO_INFO_WIDTH (&info),
            GST_VIDEO_INFO_HEIGHT (&info), 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
        if (got_gl_error ("glTexImage2D"))
          goto mem_error;

        image =
            eglCreateImageKHR (gst_egl_display_get (display),
            eglcontext, EGL_GL_TEXTURE_2D_KHR,
            (EGLClientBuffer) (guintptr) data->texture, NULL);
        if (got_egl_error ("eglCreateImageKHR"))
          goto mem_error;

        mem[0] =
            gst_egl_image_allocator_wrap (allocator, display,
            image, GST_VIDEO_GL_TEXTURE_TYPE_RGB,
            flags, size, data, (GDestroyNotify) gst_egl_gles_image_data_free);
        n_mem = 1;
      }
      break;
    }
    case GST_VIDEO_FORMAT_RGB16:{
      EGLImageKHR image;
      gsize size;

      mem[0] =
          gst_egl_image_allocator_alloc (allocator, display,
          GST_VIDEO_GL_TEXTURE_TYPE_RGB, GST_VIDEO_INFO_WIDTH (&info),
          GST_VIDEO_INFO_HEIGHT (&info), &size);
      if (mem[0]) {
        stride[0] = size / GST_VIDEO_INFO_HEIGHT (&info);
        n_mem = 1;
        GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE);
      } else {
        data = g_slice_new0 (GstEGLGLESImageData);

        stride[0] = GST_ROUND_UP_4 (GST_VIDEO_INFO_WIDTH (&info) * 2);
        size = stride[0] * GST_VIDEO_INFO_HEIGHT (&info);

        glGenTextures (1, &data->texture);
        if (got_gl_error ("glGenTextures"))
          goto mem_error;

        glBindTexture (GL_TEXTURE_2D, data->texture);
        if (got_gl_error ("glBindTexture"))
          goto mem_error;

        /* Set 2D resizing params */
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        /* If these are not set the texture image unit will return
         * * (R, G, B, A) = black on glTexImage2D for non-POT width/height
         * * frames. For a deeper explanation take a look at the OpenGL ES
         * * documentation for glTexParameter */
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        if (got_gl_error ("glTexParameteri"))
          goto mem_error;

        glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB,
            GST_VIDEO_INFO_WIDTH (&info),
            GST_VIDEO_INFO_HEIGHT (&info), 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
            NULL);
        if (got_gl_error ("glTexImage2D"))
          goto mem_error;

        image =
            eglCreateImageKHR (gst_egl_display_get (display),
            eglcontext, EGL_GL_TEXTURE_2D_KHR,
            (EGLClientBuffer) (guintptr) data->texture, NULL);
        if (got_egl_error ("eglCreateImageKHR"))
          goto mem_error;

        mem[0] =
            gst_egl_image_allocator_wrap (allocator, display,
            image, GST_VIDEO_GL_TEXTURE_TYPE_RGB,
            flags, size, data, (GDestroyNotify) gst_egl_gles_image_data_free);
        n_mem = 1;
      }
      break;
    }
    case GST_VIDEO_FORMAT_NV12:
    case GST_VIDEO_FORMAT_NV21:{
      EGLImageKHR image;
      gsize size[2];

      mem[0] =
          gst_egl_image_allocator_alloc (allocator, display,
          GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE, GST_VIDEO_INFO_COMP_WIDTH (&info,
              0), GST_VIDEO_INFO_COMP_HEIGHT (&info, 0), &size[0]);
      mem[1] =
          gst_egl_image_allocator_alloc (allocator, display,
          GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA,
          GST_VIDEO_INFO_COMP_WIDTH (&info, 1),
          GST_VIDEO_INFO_COMP_HEIGHT (&info, 1), &size[1]);

      if (mem[0] && mem[1]) {
        stride[0] = size[0] / GST_VIDEO_INFO_HEIGHT (&info);
        offset[1] = size[0];
        stride[1] = size[1] / GST_VIDEO_INFO_HEIGHT (&info);
        n_mem = 2;
        GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE);
        GST_MINI_OBJECT_FLAG_SET (mem[1], GST_MEMORY_FLAG_NO_SHARE);
      } else {
        if (mem[0])
          gst_memory_unref (mem[0]);
        if (mem[1])
          gst_memory_unref (mem[1]);
        mem[0] = mem[1] = NULL;

        stride[0] = GST_ROUND_UP_4 (GST_VIDEO_INFO_COMP_WIDTH (&info, 0));
        stride[1] = GST_ROUND_UP_4 (GST_VIDEO_INFO_COMP_WIDTH (&info, 1) * 2);
        offset[1] = stride[0] * GST_VIDEO_INFO_COMP_HEIGHT (&info, 0);
        size[0] = offset[1];
        size[1] = stride[1] * GST_VIDEO_INFO_COMP_HEIGHT (&info, 1);

        for (i = 0; i < 2; i++) {
          data = g_slice_new0 (GstEGLGLESImageData);

          glGenTextures (1, &data->texture);
          if (got_gl_error ("glGenTextures"))
            goto mem_error;

          glBindTexture (GL_TEXTURE_2D, data->texture);
          if (got_gl_error ("glBindTexture"))
            goto mem_error;

          /* Set 2D resizing params */
          glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
          glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

          /* If these are not set the texture image unit will return
           * * (R, G, B, A) = black on glTexImage2D for non-POT width/height
           * * frames. For a deeper explanation take a look at the OpenGL ES
           * * documentation for glTexParameter */
          glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
          glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
          if (got_gl_error ("glTexParameteri"))
            goto mem_error;

          if (i == 0)
            glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE,
                GST_VIDEO_INFO_COMP_WIDTH (&info, i),
                GST_VIDEO_INFO_COMP_HEIGHT (&info, i), 0, GL_LUMINANCE,
                GL_UNSIGNED_BYTE, NULL);
          else
            glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA,
                GST_VIDEO_INFO_COMP_WIDTH (&info, i),
                GST_VIDEO_INFO_COMP_HEIGHT (&info, i), 0, GL_LUMINANCE_ALPHA,
                GL_UNSIGNED_BYTE, NULL);

          if (got_gl_error ("glTexImage2D"))
            goto mem_error;

          image =
              eglCreateImageKHR (gst_egl_display_get (display),
              eglcontext, EGL_GL_TEXTURE_2D_KHR,
              (EGLClientBuffer) (guintptr) data->texture, NULL);
          if (got_egl_error ("eglCreateImageKHR"))
            goto mem_error;

          mem[i] =
              gst_egl_image_allocator_wrap (allocator, display,
              image,
              (i ==
                  0 ? GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE :
                  GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA),
              flags, size[i], data,
              (GDestroyNotify) gst_egl_gles_image_data_free);
        }

        n_mem = 2;
      }
      break;
    }
    case GST_VIDEO_FORMAT_I420:
    case GST_VIDEO_FORMAT_YV12:
    case GST_VIDEO_FORMAT_Y444:
    case GST_VIDEO_FORMAT_Y42B:
    case GST_VIDEO_FORMAT_Y41B:{
      EGLImageKHR image;
      gsize size[3];

      mem[0] =
          gst_egl_image_allocator_alloc (allocator, display,
          GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE, GST_VIDEO_INFO_COMP_WIDTH (&info,
              0), GST_VIDEO_INFO_COMP_HEIGHT (&info, 0), &size[0]);
      mem[1] =
          gst_egl_image_allocator_alloc (allocator, display,
          GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE, GST_VIDEO_INFO_COMP_WIDTH (&info,
              1), GST_VIDEO_INFO_COMP_HEIGHT (&info, 1), &size[1]);
      mem[2] =
          gst_egl_image_allocator_alloc (allocator, display,
          GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE, GST_VIDEO_INFO_COMP_WIDTH (&info,
              2), GST_VIDEO_INFO_COMP_HEIGHT (&info, 2), &size[2]);

      if (mem[0] && mem[1] && mem[2]) {
        stride[0] = size[0] / GST_VIDEO_INFO_HEIGHT (&info);
        offset[1] = size[0];
        stride[1] = size[1] / GST_VIDEO_INFO_HEIGHT (&info);
        offset[2] = size[1];
        stride[2] = size[2] / GST_VIDEO_INFO_HEIGHT (&info);
        n_mem = 3;
        GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE);
        GST_MINI_OBJECT_FLAG_SET (mem[1], GST_MEMORY_FLAG_NO_SHARE);
        GST_MINI_OBJECT_FLAG_SET (mem[2], GST_MEMORY_FLAG_NO_SHARE);
      } else {
        if (mem[0])
          gst_memory_unref (mem[0]);
        if (mem[1])
          gst_memory_unref (mem[1]);
        if (mem[2])
          gst_memory_unref (mem[2]);
        mem[0] = mem[1] = mem[2] = NULL;

        stride[0] = GST_ROUND_UP_4 (GST_VIDEO_INFO_COMP_WIDTH (&info, 0));
        stride[1] = GST_ROUND_UP_4 (GST_VIDEO_INFO_COMP_WIDTH (&info, 1));
        stride[2] = GST_ROUND_UP_4 (GST_VIDEO_INFO_COMP_WIDTH (&info, 2));
        size[0] = stride[0] * GST_VIDEO_INFO_COMP_HEIGHT (&info, 0);
        size[1] = stride[1] * GST_VIDEO_INFO_COMP_HEIGHT (&info, 1);
        size[2] = stride[2] * GST_VIDEO_INFO_COMP_HEIGHT (&info, 2);
        offset[0] = 0;
        offset[1] = size[0];
        offset[2] = offset[1] + size[1];

        for (i = 0; i < 3; i++) {
          data = g_slice_new0 (GstEGLGLESImageData);

          glGenTextures (1, &data->texture);
          if (got_gl_error ("glGenTextures"))
            goto mem_error;

          glBindTexture (GL_TEXTURE_2D, data->texture);
          if (got_gl_error ("glBindTexture"))
            goto mem_error;

          /* Set 2D resizing params */
          glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
          glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

          /* If these are not set the texture image unit will return
           * * (R, G, B, A) = black on glTexImage2D for non-POT width/height
           * * frames. For a deeper explanation take a look at the OpenGL ES
           * * documentation for glTexParameter */
          glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
          glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
          if (got_gl_error ("glTexParameteri"))
            goto mem_error;

          glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE,
              GST_VIDEO_INFO_COMP_WIDTH (&info, i),
              GST_VIDEO_INFO_COMP_HEIGHT (&info, i), 0, GL_LUMINANCE,
              GL_UNSIGNED_BYTE, NULL);

          if (got_gl_error ("glTexImage2D"))
            goto mem_error;

          image =
              eglCreateImageKHR (gst_egl_display_get (display),
              eglcontext, EGL_GL_TEXTURE_2D_KHR,
              (EGLClientBuffer) (guintptr) data->texture, NULL);
          if (got_egl_error ("eglCreateImageKHR"))
            goto mem_error;

          mem[i] =
              gst_egl_image_allocator_wrap (allocator, display,
              image, GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE,
              flags, size[i], data,
              (GDestroyNotify) gst_egl_gles_image_data_free);
        }

        n_mem = 3;
      }
      break;
    }
    case GST_VIDEO_FORMAT_RGBA:
    case GST_VIDEO_FORMAT_BGRA:
    case GST_VIDEO_FORMAT_ARGB:
    case GST_VIDEO_FORMAT_ABGR:
    case GST_VIDEO_FORMAT_RGBx:
    case GST_VIDEO_FORMAT_BGRx:
    case GST_VIDEO_FORMAT_xRGB:
    case GST_VIDEO_FORMAT_xBGR:
    case GST_VIDEO_FORMAT_AYUV:{
      gsize size;
      EGLImageKHR image;

      mem[0] =
          gst_egl_image_allocator_alloc (allocator, display,
          GST_VIDEO_GL_TEXTURE_TYPE_RGBA, GST_VIDEO_INFO_WIDTH (&info),
          GST_VIDEO_INFO_HEIGHT (&info), &size);
      if (mem[0]) {
        stride[0] = size / GST_VIDEO_INFO_HEIGHT (&info);
        n_mem = 1;
        GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE);
      } else {
        data = g_slice_new0 (GstEGLGLESImageData);

        stride[0] = GST_ROUND_UP_4 (GST_VIDEO_INFO_WIDTH (&info) * 4);
        size = stride[0] * GST_VIDEO_INFO_HEIGHT (&info);

        glGenTextures (1, &data->texture);
        if (got_gl_error ("glGenTextures"))
          goto mem_error;

        glBindTexture (GL_TEXTURE_2D, data->texture);
        if (got_gl_error ("glBindTexture"))
          goto mem_error;

        /* Set 2D resizing params */
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        /* If these are not set the texture image unit will return
         * * (R, G, B, A) = black on glTexImage2D for non-POT width/height
         * * frames. For a deeper explanation take a look at the OpenGL ES
         * * documentation for glTexParameter */
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        if (got_gl_error ("glTexParameteri"))
          goto mem_error;

        glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA,
            GST_VIDEO_INFO_WIDTH (&info),
            GST_VIDEO_INFO_HEIGHT (&info), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
        if (got_gl_error ("glTexImage2D"))
          goto mem_error;

        image =
            eglCreateImageKHR (gst_egl_display_get (display),
            eglcontext, EGL_GL_TEXTURE_2D_KHR,
            (EGLClientBuffer) (guintptr) data->texture, NULL);
        if (got_egl_error ("eglCreateImageKHR"))
          goto mem_error;

        mem[0] =
            gst_egl_image_allocator_wrap (allocator, display,
            image, GST_VIDEO_GL_TEXTURE_TYPE_RGBA,
            flags, size, data, (GDestroyNotify) gst_egl_gles_image_data_free);

        n_mem = 1;
      }
      break;
    }
    default:
      g_assert_not_reached ();
      break;
  }

  buffer = gst_buffer_new ();
  gst_buffer_add_video_meta_full (buffer, 0, format, width, height,
      GST_VIDEO_INFO_N_PLANES (&info), offset, stride);

  for (i = 0; i < n_mem; i++)
    gst_buffer_append_memory (buffer, mem[i]);

  return buffer;

mem_error:
  {
    GST_ERROR_OBJECT (GST_CAT_DEFAULT, "Failed to create EGLImage");

    if (data)
      gst_egl_gles_image_data_free (data);

    if (mem[0])
      gst_memory_unref (mem[0]);
    if (mem[1])
      gst_memory_unref (mem[1]);
    if (mem[2])
      gst_memory_unref (mem[2]);

    return NULL;
  }
}
Esempio n. 5
0
bool FBO::init(int width, int height, GraphicsContext3D::Attributes attributes)
{
#if !USE(SHARED_TEXTURE_WEBGL)
    // 1. Allocate a graphic buffer
    sp<ISurfaceComposer> composer(ComposerService::getComposerService());
    m_graphicBufferAlloc = composer->createGraphicBufferAlloc();

    status_t error;

    PixelFormat format = attributes.alpha ? HAL_PIXEL_FORMAT_RGBA_8888 : HAL_PIXEL_FORMAT_RGBX_8888;

    m_grBuffer = m_graphicBufferAlloc->createGraphicBuffer(width, height, format,
                 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_HW_TEXTURE, &error);
    if (error != NO_ERROR) {
        LOGWEBGL(" failed to allocate GraphicBuffer, error = %d", error);
        return false;
    }

    void *addr = 0;
    if (m_grBuffer->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, &addr) != NO_ERROR) {
        LOGWEBGL("  failed to lock the GraphicBuffer");
        return false;
    }
    // WebGL requires all buffers to be initialized to 0.
    memset(addr, 0, width * height * 4);
    m_grBuffer->unlock();

    ANativeWindowBuffer* clientBuf = m_grBuffer->getNativeBuffer();
    if (clientBuf->handle == 0) {
        LOGWEBGL(" empty handle in GraphicBuffer");
        return false;
    }

    // 2. Create an EGLImage from the graphic buffer
    const EGLint attrs[] = {
        EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
        EGL_NONE,                EGL_NONE
    };

    m_image = eglCreateImageKHR(m_dpy,
                                EGL_NO_CONTEXT,
                                EGL_NATIVE_BUFFER_ANDROID,
                                (EGLClientBuffer)clientBuf,
                                attrs);
    if (GraphicsContext3DInternal::checkEGLError("eglCreateImageKHR") != EGL_SUCCESS) {
        LOGWEBGL("eglCreateImageKHR() failed");
        return false;
    }
#endif
    // 3. Create a texture from the EGLImage
    m_texture = createTexture(m_image, width, height);

    if (m_texture == 0) {
        LOGWEBGL("createTexture() failed");
        return false;
    }

    // 4. Create the Framebuffer Object from the texture
    glGenFramebuffers(1, &m_fbo);

    if (attributes.depth) {
        glGenRenderbuffers(1, &m_depthBuffer);
        glBindRenderbuffer(GL_RENDERBUFFER, m_depthBuffer);
        glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
        if (GraphicsContext3DInternal::checkGLError("glRenderbufferStorage") != GL_NO_ERROR)
            return false;
    }

    if (attributes.stencil) {
        glGenRenderbuffers(1, &m_stencilBuffer);
        glBindRenderbuffer(GL_RENDERBUFFER, m_stencilBuffer);
        glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, width, height);
        if (GraphicsContext3DInternal::checkGLError("glRenderbufferStorage") != GL_NO_ERROR)
            return false;
    }

    glBindRenderbuffer(GL_RENDERBUFFER, 0);

    glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture, 0);
    if (GraphicsContext3DInternal::checkGLError("glFramebufferTexture2D") != GL_NO_ERROR)
        return false;

    if (attributes.depth) {
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthBuffer);
        if (GraphicsContext3DInternal::checkGLError("glFramebufferRenderbuffer") != GL_NO_ERROR)
            return false;
    }

    if (attributes.stencil) {
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_stencilBuffer);
        if (GraphicsContext3DInternal::checkGLError("glFramebufferRenderbuffer") != GL_NO_ERROR)
            return false;
    }

    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    if (status != GL_FRAMEBUFFER_COMPLETE) {
        LOGWEBGL("Framebuffer incomplete: %d", status);
        return false;
    }

    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    return true;
}
Esempio n. 6
0
bool camera_read_frame(void){
	if(MMAL_BUFFER_HEADER_T* buf = mmal_queue_get(video_queue)){
	
		//mmal_buffer_header_mem_lock(buf);
		
		//printf("Buffer received with length %d\n", buf->length);
	
		glBindTexture(GL_TEXTURE_EXTERNAL_OES, cam_ytex);
		check();
		if(yimg != EGL_NO_IMAGE_KHR){
			eglDestroyImageKHR(GDisplay, yimg);
			yimg = EGL_NO_IMAGE_KHR;
		}
		yimg = eglCreateImageKHR(GDisplay, 
			EGL_NO_CONTEXT, 
			EGL_IMAGE_BRCM_MULTIMEDIA_Y, 
			(EGLClientBuffer) buf->data, 
			NULL);
		check();
		glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, yimg);
		check();
		
		glBindTexture(GL_TEXTURE_EXTERNAL_OES, cam_utex);
		check();
		if(uimg != EGL_NO_IMAGE_KHR){
			eglDestroyImageKHR(GDisplay, uimg);
			uimg = EGL_NO_IMAGE_KHR;
		}
		uimg = eglCreateImageKHR(GDisplay, 
			EGL_NO_CONTEXT, 
			EGL_IMAGE_BRCM_MULTIMEDIA_U, 
			(EGLClientBuffer) buf->data, 
			NULL);
		check();
		glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, uimg);
		check();
		
		glBindTexture(GL_TEXTURE_EXTERNAL_OES, cam_vtex);
		check();
		if(vimg != EGL_NO_IMAGE_KHR){
			eglDestroyImageKHR(GDisplay, vimg);
			vimg = EGL_NO_IMAGE_KHR;
		}
		vimg = eglCreateImageKHR(GDisplay, 
			EGL_NO_CONTEXT, 
			EGL_IMAGE_BRCM_MULTIMEDIA_V, 
			(EGLClientBuffer) buf->data, 
			NULL);
		check();
		glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, vimg);
		check();
		
		//mmal_buffer_header_mem_unlock(buf);
		mmal_buffer_header_release(buf);
		
		if(preview_port->is_enabled){
			MMAL_STATUS_T status;
			MMAL_BUFFER_HEADER_T *new_buffer;
			new_buffer = mmal_queue_get(video_pool->queue);
			if (new_buffer)
				status = mmal_port_send_buffer(preview_port, new_buffer);
			if (!new_buffer || status != MMAL_SUCCESS)
				printf("Unable to return a buffer to the video port\n\n");
		}
		
		return true;
	}
	
	return false; //no buffer received
}
Esempio n. 7
0
int main(void)
{
	EGLint major, minor, eglCfgCount, eglCfgVisualId, width, height;
	const IMG_gralloc_module_public_t *module;
	buffer_handle_t srcBuffer, destBuffer;
	EGLImageKHR eglSrcImage, eglDestImage;
	EGLConfig eglConfig, eglFBConfig;
	GLuint fboName, textureNames[2];
	EGLNativeWindowType eglWindow;
	EGLSurface eglWindowSurface;
	alloc_device_t *device;
	EGLContext eglContext;
	EGLDisplay eglDisplay;
	int err = 1, stride;
	GLenum glError;

	ANativeWindowBuffer sSrcBuffer =
	{
		.common.magic	= ANDROID_NATIVE_BUFFER_MAGIC,
		.common.version	= sizeof(ANativeWindowBuffer),
		.common.incRef	= incRefNop,
		.common.decRef	= decRefNop,
		.width			= SRC_WIDTH,
		.height			= SRC_HEIGHT,
		.stride			= SRC_STRIDE,
		.usage			= GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE,
	};

	ANativeWindowBuffer sDestBuffer =
	{
		.common.magic	= ANDROID_NATIVE_BUFFER_MAGIC,
		.common.version	= sizeof(ANativeWindowBuffer),
		.common.incRef	= incRefNop,
		.common.decRef	= decRefNop,
		.width			= DEST_WIDTH,
		.height			= DEST_HEIGHT,
		.stride			= DEST_STRIDE,
		.format			= DEST_FORMAT,
		.usage			= GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE,
	};

	EGLint eglCfgAttribs[] =
	{
		EGL_RED_SIZE,			5,
		EGL_GREEN_SIZE,			6,
		EGL_BLUE_SIZE,			5,
		EGL_ALPHA_SIZE,			0,
		EGL_SURFACE_TYPE,		EGL_WINDOW_BIT,
		EGL_RENDERABLE_TYPE,	EGL_OPENGL_ES_BIT,
#ifdef EGL_ANDROID_recordable
		EGL_RECORDABLE_ANDROID,	EGL_TRUE,
#endif
		EGL_NONE,
	};

	const float srcVertexArray[2 * 4] = {
		 0.0f,	 1.0f,
		 0.0f,	 0.0f,
		 1.0f, 	 1.0f,
		 1.0f,	 0.0f,
	};

	const float texCoordArray[2 * 4] = {
		 0.0f,	 0.0f,
		 0.0f,	 1.0f,
		 1.0f,	 0.0f,
		 1.0f,	 1.0f,
	};

	const float destVertexArray[2 * 4] = {
		-1.0f,	 0.0f,
		-1.0f,	-1.0f,
		 0.0f,	 0.0f,
		 0.0f,	-1.0f,
	};

	eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
	if(eglDisplay == EGL_NO_DISPLAY)
	{
		printf("eglGetDisplay failed\n");
		goto err_out;
	}

	if(!eglInitialize(eglDisplay, &major, &minor))
	{
		printf("eglInitialize failed (err=0x%x)\n", eglGetError());
		goto err_out;
	}

	if(!eglChooseConfig(eglDisplay, eglCfgAttribs,
						&eglConfig, 1, &eglCfgCount))
	{
		printf("eglChooseConfig failed (err=0x%x)\n", eglGetError());
		goto err_terminate;
	}

	if(!eglCfgCount)
	{
		printf("eglChooseConfig found no suitable configs\n");
		goto err_terminate;
	}

	if(!eglGetConfigAttrib(eglDisplay, eglConfig,
						   EGL_NATIVE_VISUAL_ID, &eglCfgVisualId))
	{
		printf("eglGetConfigAttrib failed (err=0x%x)\n", eglGetError());
		goto err_terminate;
	}

	sSrcBuffer.format = eglCfgVisualId;

	/* Handle FB rendering ***************************************************/

	eglWindow = android_createDisplaySurface();
	if(!eglWindow)
	{
		printf("android_createDisplaySurface returned NULL\n");
		goto err_terminate;
	}

	eglWindow->common.incRef(&eglWindow->common);

	eglFBConfig = findMatchingWindowConfig(eglDisplay, EGL_OPENGL_ES_BIT, eglWindow);
	/* FIXME: findMatchingWindowConfig returns no error code */

	eglContext = eglCreateContext(eglDisplay, eglFBConfig, EGL_NO_CONTEXT, NULL);
	if(eglContext == EGL_NO_CONTEXT)
	{
		printf("eglCreateContext failed (err=0x%x)\n", eglGetError());
		goto err_window_decref;
	}

	eglWindowSurface = eglCreateWindowSurface(eglDisplay, eglFBConfig, eglWindow, NULL);
	if(eglWindowSurface == EGL_NO_SURFACE)
	{
		printf("eglCreateWindowSurface failed (err=0x%x)\n", eglGetError());
		goto err_destroy_context;
	}

	if(!eglQuerySurface(eglDisplay, eglWindowSurface, EGL_WIDTH, &width))
	{
		printf("eglQuerySurface #1 failed (err=0x%x)\n", eglGetError());
		goto err_destroy_context;
	}

	if(!eglQuerySurface(eglDisplay, eglWindowSurface, EGL_HEIGHT, &height))
	{
		printf("eglQuerySurface #2 failed (err=0x%x)\n", eglGetError());
		goto err_destroy_context;
	}

	if(!eglMakeCurrent(eglDisplay, eglWindowSurface, eglWindowSurface, eglContext))
	{
		printf("eglMakeCurrent failed (err=0x%x)\n", eglGetError());
		goto err_destroy_surface;
	}

	/* Allocate some compatible buffers with gralloc *************************/

	err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
						(const hw_module_t **)&module);
	if(err)
	{
		printf("hw_get_module failed (err=%d)\n", err);
		goto err_make_non_current;
	}

	err = module->base.common.methods->open((const hw_module_t *)module,
											GRALLOC_HARDWARE_GPU0,
											(hw_device_t **)&device);
	if(err)
	{
		printf("module->common.methods->open() failed (err=%d)\n", err);
		goto err_make_non_current;
	}

	err = device->alloc(device, SRC_WIDTH, SRC_HEIGHT, eglCfgVisualId,
						GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE,
						&srcBuffer, &stride);
	if(err)
	{
		printf("device->alloc() failed (err=%d)\n", err);
		goto err_close;
	}

	err = device->alloc(device, DEST_WIDTH, DEST_HEIGHT, DEST_FORMAT,
						GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE,
						&destBuffer, &stride);
	if(err)
	{
		printf("device->alloc() failed (err=%d)\n", err);
		goto err_free_src;
	}

	err = module->base.registerBuffer(&module->base, srcBuffer);
	if(err)
	{
		printf("module->registerBuffer() failed (err=%d)\n", err);
		goto err_free_dest;
	}

	err = module->base.registerBuffer(&module->base, destBuffer);
	if(err)
	{
		printf("module->registerBuffer() failed (err=%d)\n", err);
		goto err_unregister_src;
	}

	sSrcBuffer.handle = srcBuffer;
	sDestBuffer.handle = destBuffer;

	/* Make some EGLImageKHRs out of them ************************************/

	eglSrcImage = eglCreateImageKHR(eglDisplay, EGL_NO_CONTEXT,
									EGL_NATIVE_BUFFER_ANDROID,
									(EGLClientBuffer)&sSrcBuffer, 0);
	if(eglSrcImage == EGL_NO_IMAGE_KHR)
	{
		printf("eglCreateImageKHR #1 failed (err=0x%x)\n", eglGetError());
		goto err_unregister_dest;
	}

	eglDestImage = eglCreateImageKHR(eglDisplay, EGL_NO_CONTEXT,
									 EGL_NATIVE_BUFFER_ANDROID,
									 (EGLClientBuffer)&sDestBuffer, 0);
	if(eglDestImage == EGL_NO_IMAGE_KHR)
	{
		printf("eglCreateImageKHR #2 failed (err=0x%x)\n", eglGetError());
		goto err_destroy_src_image;
	}

	/* Create funny textures *************************************************/

	glGenTextures(2, textureNames);
	glError = glGetError();
	if(glError != GL_NO_ERROR)
	{
		printf("glGenTextures generated error 0x%x\n", glError);
		goto err_destroy_dest_image;
	}

	glBindTexture(GL_TEXTURE_2D, textureNames[0]);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

	glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, eglSrcImage);
	glError = glGetError();
	if(glError != GL_NO_ERROR)
	{
		printf("glEGLImageTargetTexture2DOES generated error 0x%x\n", glError);
		goto err_delete_textures;
	}

	glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureNames[1]);
	glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

	glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, eglDestImage);
	glError = glGetError();
	if(glError != GL_NO_ERROR)
	{
		printf("glEGLImageTargetTexture2DOES generated error 0x%x\n", glError);
		goto err_delete_textures;
	}

	/* Create FBO ************************************************************/

	glGenFramebuffersOES(1, &fboName);
	glError = glGetError();
	if(glError != GL_NO_ERROR)
	{
		printf("glGenFrameBuffersOES generated error 0x%x\n", glError);
		goto err_delete_textures;
	}

	glBindFramebufferOES(GL_FRAMEBUFFER_OES, fboName);
	glError = glGetError();
	if(glError != GL_NO_ERROR)
	{
		printf("glBindFramebufferOES generated error 0x%x\n", glError);
		goto err_delete_framebuffer;
	}

	glBindTexture(GL_TEXTURE_2D, textureNames[0]);

	glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES,
							  GL_TEXTURE_2D, textureNames[0], 0);
	glError = glGetError();
	if(glError != GL_NO_ERROR)
	{
		printf("glFramebufferTexture2DOES generated error 0x%x\n", glError);
		goto err_delete_framebuffer;
	}

	/*************************************************************************/

	glError = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
	if(glError != GL_FRAMEBUFFER_COMPLETE_OES)
	{
		printf("glCheckFramebufferStatus generated error 0x%x\n", glError);
		goto err_delete_framebuffer;
	}

	/* Draw some stuff */

	{
		const float vertexArray[2 * 4] = {
			-1.0f,	 1.0f,
			-1.0f,	-1.0f,
			 1.0f,	 1.0f,
			 1.0f,	-1.0f,
		};

		const float colorArray[4 * 4] = {
			 1.0f, 0.0f, 0.0f, 1.0f,
			 0.0f, 1.0f, 0.0f, 1.0f,
			 0.0f, 0.0f, 1.0f, 1.0f,
			 1.0f, 0.0f, 1.0f, 1.0f,
		};

		char dummy[4];

		glViewport(0, 0, SRC_WIDTH, SRC_HEIGHT);

		glEnableClientState(GL_VERTEX_ARRAY);
		glEnableClientState(GL_COLOR_ARRAY);

		glVertexPointer(2, GL_FLOAT, 0, vertexArray);
		glColorPointer(4, GL_FLOAT, 0, colorArray);

		glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

		glDisableClientState(GL_COLOR_ARRAY);
		glDisableClientState(GL_VERTEX_ARRAY);

		glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, dummy);
	}

	/* RGB -> YUV blit */

	err = module->Blit2(module, srcBuffer, destBuffer,
						SRC_WIDTH, SRC_HEIGHT, 0, 0);
	if(err)
	{
		printf("module->Blit2() failed (err=%d)\n", err);
		goto err_delete_framebuffer;
	}

	/* Present both to screen (should appear identical) */

	glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
	glViewport(0, 0, width, height);

	glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT);

	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);

	glTexCoordPointer(2, GL_FLOAT, 0, texCoordArray);

	glEnable(GL_TEXTURE_EXTERNAL_OES);
	glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureNames[1]);
	glVertexPointer(2, GL_FLOAT, 0, destVertexArray);
	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
	glDisable(GL_TEXTURE_EXTERNAL_OES);

	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, textureNames[0]);
	glVertexPointer(2, GL_FLOAT, 0, srcVertexArray);
	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
	glDisable(GL_TEXTURE_2D);

	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
	glDisableClientState(GL_VERTEX_ARRAY);

	eglSwapBuffers(eglDisplay, eglWindowSurface);
	sleep(1);

err_delete_framebuffer:
	glDeleteFramebuffersOES(1, &fboName);
err_delete_textures:
	glDeleteTextures(2, textureNames);
err_destroy_dest_image:
	eglDestroyImageKHR(eglDisplay, eglDestImage);
err_destroy_src_image:
	eglDestroyImageKHR(eglDisplay, eglSrcImage);
err_unregister_dest:
	err = module->base.unregisterBuffer(&module->base, destBuffer);
	if(err)
		printf("module->unregisterBuffer() failed (err=%d)\n", err);
err_unregister_src:
	err = module->base.unregisterBuffer(&module->base, srcBuffer);
	if(err)
		printf("module->unregisterBuffer() failed (err=%d)\n", err);
err_free_dest:
	err = device->free(device, destBuffer);
	if(err)
		printf("device->free() failed (err=%d)\n", err);
err_free_src:
	err = device->free(device, srcBuffer);
	if(err)
		printf("device->free() failed (err=%d)\n", err);
err_close:
	err = device->common.close((hw_device_t *)device);
	if(err)
		printf("hal->close() failed (err=%d)\n", err);
err_make_non_current:
	eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
err_destroy_surface:
	eglDestroySurface(eglDisplay, eglWindowSurface);
err_destroy_context:
	eglDestroyContext(eglDisplay, eglContext);
err_window_decref:
	eglWindow->common.decRef(&eglWindow->common);
err_terminate:
	eglTerminate(eglDisplay);
err_out:
	return err;
}
extern "C" void
Java_org_mozilla_testuniversalsurfacetexture_TestUniversalSurfaceTexture_attachTexture(JNIEnv*
    aJEnv, jclass klass, jobject aSurface, int aDestroyed)
{
    __android_log_print(ANDROID_LOG_ERROR, "TUST", "### point a");

    if (!sSurfaceClass) {
        sSurfaceClass = reinterpret_cast<jclass>
            (aJEnv->NewGlobalRef(aJEnv->FindClass("android/view/Surface")));
        sNativeSurfaceField = aJEnv->GetFieldID(sSurfaceClass, "mNativeSurface", "I");
        sSurfaceControlField = aJEnv->GetFieldID(sSurfaceClass, "mSurfaceControl", "I");

        void* lib = dlopen("libui.so", RTLD_LAZY);
        sw_gralloc_handle_t_lock = (typeof(sw_gralloc_handle_t_lock))
            dlsym(lib, "_ZN7android19sw_gralloc_handle_t4lockEPS0_iiiiiPPv");
        sw_gralloc_handle_t_unlock = (typeof(sw_gralloc_handle_t_unlock))
            dlsym(lib, "_ZN7android19sw_gralloc_handle_t6unlockEPS0_");
        __android_log_print(ANDROID_LOG_ERROR, "TUST", "### Lock=%p, unlock=%p",
                            sw_gralloc_handle_t_lock, sw_gralloc_handle_t_unlock);

        lib = dlopen("libhardware.so", RTLD_LAZY);
        hw_get_module = (typeof(hw_get_module))dlsym(lib, "hw_get_module");

        hw_module_t* pModule;
        hw_get_module("gralloc", &pModule);
        sModule = reinterpret_cast<gralloc_module_t*>(pModule);
        __android_log_print(ANDROID_LOG_ERROR, "TUST", "### Gralloc module=%p", pModule);
    }

    if (!sImage) {
        ANativeWindow* nativeWindow = reinterpret_cast<ANativeWindow*>
            (aJEnv->GetIntField(aSurface, sNativeSurfaceField) + 8);

        /*Rect rect;
        rect.left = rect.top = rect.right = rect.bottom = 0;
        nativeWindow->perform(nativeWindow, NATIVE_WINDOW_SET_CROP, &rect);*/

        // NB: nativeWindow->common.magic is '_wnd' as a FourCC.
        // My version is 104.

        __android_log_print(ANDROID_LOG_ERROR, "TUST",
                            "### Native window ptr %p, magic %08x, version %d, reserved %p, flags %d, dpi %g\n",
                            nativeWindow, (unsigned)nativeWindow->common.magic,
                            nativeWindow->common.version, nativeWindow->common.reserved[0],
                            (int)nativeWindow->flags, (double)nativeWindow->xdpi);

        nativeWindow->dequeueBuffer(nativeWindow, &sBuffer);
        nativeWindow->lockBuffer(nativeWindow, sBuffer);

        // Must increment the refcount on the native window to avoid crashes on Mali (Galaxy S2).
        nativeWindow->common.incRef(&nativeWindow->common);

        const EGLint eglImgAttrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE, EGL_NONE };

        sBuffer->common.incRef(&sBuffer->common);

        sImage = eglCreateImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY), EGL_NO_CONTEXT,
                                     EGL_NATIVE_BUFFER_ANDROID,
                                     reinterpret_cast<EGLClientBuffer>(sBuffer), eglImgAttrs);

        //nativeWindow->queueBuffer(nativeWindow, sBuffer);
    }

    uint8_t *bits = 0;
    int err = sModule->lock(sModule, sBuffer->handle, GRALLOC_USAGE_SW_READ_OFTEN |
                            GRALLOC_USAGE_SW_WRITE_OFTEN, 0, 0, 512, 512, (void**)&bits);
    __android_log_print(ANDROID_LOG_ERROR, "TUST",
                "### Buffer width=%d height=%d stride=%d format=%d usage=%d Bits are: %p, err=%d",
                sBuffer->width, sBuffer->height, sBuffer->stride, sBuffer->format, sBuffer->usage,
                bits, err);

    struct timeval tv;
    gettimeofday(&tv, NULL);

    static int x = 0;

    for (int i = 0; i < 512*512*2; i += 2) {
        bits[i] = bits[i+1] = (tv.tv_usec / 100000) % 256;
    }
    sModule->unlock(sModule, sBuffer->handle);

    glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, sImage);

    __android_log_print(ANDROID_LOG_ERROR, "TUST", "### Success! GL error is: %d",
                        (int)glGetError());
}