How to render the EGL image (from fd) to a frame buffer?

I’m trying like crazy to render to a frame buffer the egl image that I receive from the decoder through file descriptor.

This is my sketch code. It creates two textures, frameBufferTexture and externalTexture. We write our EGLImage to externalTexture and draw to frameBufferTexture from externalTexture. Then we bind frameBUfferTexture to read from it with glReadPixels:

glGenFramebuffers(1, &frameBuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
    //externalTexture is the texture I'm gonna send the eglImage
    glGenTextures(1, &externalTexture);
    //bufferTexture is where we're going to render to
    glGenTextures(1, &frameBufferTexture);
    //Lines below create an empty texture with our image size (I'm assuming its RGBA, I don't know)
    glBindTexture(GL_TEXTURE_2D, externalTexture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, decodedNvFrame->width, decodedNvFrame->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
    //Tells the shader which texture unit we're using
    glUniform1i(texLocation, 0);
    //Don't know what these are for, exactly
    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_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    //Binds our frameBuffer because we're going to write to it
    glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
    glBindTexture(GL_TEXTURE_2D, frameBufferTexture);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, frameBufferTexture, 0);
    
    //Activate externalTexture because we want to put our hEglImage image there
    glBindTexture(GL_TEXTURE_2D, externalTexture);
    EGLImageKHR hEglImage;
    EGLSyncKHR eglSync;
    hEglImage = NvEGLImageFromFd(eglDisplay, decodedNvFrame->nvBuffer->planes[0].fd);
    //Puts hEglImage into externalTexture?
    glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, hEglImage);
    glBindVertexArray(vertexArrayObject);
    //Draw to our frame buffer using the texture from externalTexture
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    //Bind frameBufferTexture because we're going to read data from it with glReadPixels
    glBindTexture(GL_TEXTURE_2D, frameBufferTexture);
    //-------------
    glReadBuffer(GL_COLOR_ATTACHMENT0);
    //Just pick a small 512x512 image so we can see in the console if numbers appear 'random'
    glReadPixels(0, 0, 512, 512, GL_RGBA, GL_UNSIGNED_BYTE, r);

    for (int i = 0; i < 100; ++i)
    {
        printf("%i ", r[i]);
    }
    printf("\n");

The problem is that I get error at

glReadBuffer(GL_COLOR_ATTACHMENT0);

Here’s the fragment shader:

#version 330 core
    out vec4 FragColor;
    
    in vec2 TexCoord;
    uniform sampler2D tex;
    
    void main()
    {
    	FragColor = texture(tex, TexCoord);
    }

I also tried changing my fragment shader to

#version 330 core
#extension GL_OES_EGL_image_external : require
precision mediump float;
out vec4 FragColor;

in vec2 TexCoord;
uniform samplerExternalOES tex;

void main()
{
	FragColor = texture2D(tex, TexCoord);
}

then binding

externalTexture

like this:

glBindTexture(GL_TEXTURE_EXTERNAL_OES, externalTexture);

but it also didn’t work

So how to render to a frame buffer?

1 Like

Hi,
We have existing implementations. Please refer to

tegra_multimedia_api\argus\samples\utils\PreviewConsumer.cpp
tegra_multimedia_api\samples\common\classes\NvEglRenderer.cpp

unfortunately these examples don’t render to a frame buffer! I’m looking to a texture. Please take a look:

glGenFramebuffers(1, &frameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
glGenTextures(1, &externalTexture);
glGenTextures(1, &frameBufferTexture);
glBindTexture(GL_TEXTURE_2D, frameBufferTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, decodedNvFrame->width, decodedNvFrame->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glUniform1i(texLocation, 0);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
glBindTexture(GL_TEXTURE_2D, frameBufferTexture);

EGLImageKHR hEglImage;

hEglImage = NvEGLImageFromFd(eglDisplay, decodedNvFrame->nvBuffer->planes[0].fd);
if (!hEglImage)
    printf("Could not get EglImage from fd. Not rendering\n");
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, frameBufferTexture, 0);		
glBindTexture(GL_TEXTURE_2D, externalTexture);
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, hEglImage);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glUniform1i(texLocation, 0);
glBindVertexArray(vertexArrayObject);
    
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

glReadBuffer(GL_COLOR_ATTACHMENT0);

GLenum frameBufferStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (frameBufferStatus!=GL_FRAMEBUFFER_COMPLETE) {
    printf("frameBufferStatus problem!\n");
    abort();
}
glReadPixels(0, 0, 512, 512, GL_RGBA, GL_UNSIGNED_BYTE, r);

for (int i = 0; i < 100; ++i)
{
    printf("%i ", r[i]);
}
printf("\n");

NvDestroyEGLImage(eglDisplay, hEglImage);

I get no openl errors with this code but I only read this

0 0 0 255 0 0 0 255 0 0 0 255...

which means the

glEGLImageTargetTexture2DOES

line isn’t doing what it should do. Why it’s not sending the texture?

glGenFramebuffers(1, &frameBuffer);
        glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
        glGenTextures(1, &externalTexture);
        glGenTextures(1, &frameBufferTexture);
        glBindTexture(GL_TEXTURE_2D, frameBufferTexture);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, decodedNvFrame->width, decodedNvFrame->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
        glUniform1i(texLocation, 0);
    
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

	glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
	glBindTexture(GL_TEXTURE_2D, frameBufferTexture);
	
	EGLImageKHR hEglImage;

	hEglImage = NvEGLImageFromFd(eglDisplay, decodedNvFrame->nvBuffer->planes[0].fd);
	if (!hEglImage)
		printf("Could not get EglImage from fd. Not rendering\n");
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, frameBufferTexture, 0);		
	glBindTexture(GL_TEXTURE_2D, externalTexture);
	//-----------------------------------------------------
	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_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, d);
	//-----------------------------------------------------
	glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, hEglImage);
	glUniform1i(texLocation, 0);
	glBindVertexArray(vertexArrayObject);
		
	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

	glReadBuffer(GL_COLOR_ATTACHMENT0);

	GLenum frameBufferStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
        if (frameBufferStatus!=GL_FRAMEBUFFER_COMPLETE) {
		printf("frameBufferStatus problem!\n");
		abort();
	}
	glReadPixels(0, 0, 512, 512, GL_RGBA, GL_UNSIGNED_BYTE, r);

	for (int i = 0; i < 100; ++i)
	{
		printf("%i ", r[i]);
	}
	printf("\n");

	NvDestroyEGLImage(eglDisplay, hEglImage);

Take a look at the dot inserted lines. If I compile without them, I get the 0 0 0 255 result. If I add those 5 lines, I get, in the output, the exact contents of d. This means that the problem is that glEGLImageTargetTexture2DOES fails to write my image to

externalTexture

, and therefore my fragment shader draws from an empty externalTexture. When a

glTexImage2D

is added, it draws from a filled externalTexture. So the shader is indeed working, and the problem is in the glEGLImageTargetTexture2DOES call.

So how to use

glEGLImageTargetTexture2DOES

the rigth way?

Hi,
Please share a patch so that we can reproduce the error case you are hitting. 00_video_decode can be a good sample.

You can modify the color format to have RGBA NvBuffer:

input_params.payloadType = NvBufferPayload_SurfArray;
input_params.width = crop.c.width;
input_params.height = crop.c.height;
input_params.layout = NvBufferLayout_Pitch;
<b>input_params.colorFormat = NvBufferColorFormat_ABGR32;</b>
input_params.nvbuf_tag = NvBufferTag_VIDEO_DEC;

ret = NvBufferCreateEx (&ctx->dst_dma_fd, &input_params);
TEST_ERROR(ret == -1, "create dmabuf failed", error);

And below code in NvEglRenderer.cpp to your usecase:

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_id);
glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, hEglImage);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1 Like

Hi, I managed to simulate a decoded image through

NvBufferCreateEx

as you suggested. When the EGL context is created with

egl_surface = eglCreatePbufferSurface(egl_display, egl_config, pbuffer_attrib_list);
    egl_context = eglCreateContext(egl_display, egl_config, EGL_NO_CONTEXT, context_attrib_list);
    eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context);

the call

glEGLImageTargetTexture2DOES

works.

When it’s created with

egl_context = eglCreateContext(egl_display, egl_config, EGL_NO_CONTEXT, context_attrib_list);
    eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, egl_context);

then

glEGLImageTargetTexture2DOES

does nothing, but all the rest work.

The problem with this is that

  1. I don’t think I should need a pbuffer surface (and I’ve read that there are limitations to pbuffer that there are not present in frame buffer)

  2. I cannot integrate this code with GTK, because somehow, GTK automatically creates an Open GL context when the signal_render signal is called and I don’t think I can turn it off. This automatic Open GL context seems to override the egl_surface or something related to it, because glEGLImageTargetTexture2DOESwill not work when called from GTK code, even if I try to call eglMakeCurrent inside every render, and even if I use pBuffer surface at the EGL creation

#include <epoxy/gl.h>
#include <EGL/egl.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <stdio.h>
#include <stdlib.h>
#include <nvbuf_utils.h>
#include <string>
#include <stdexcept>
#include <iostream>
#include <sstream>

const char *vertex_shader = R"glsl(
      #version 100
      attribute vec2 position;
      attribute vec2 tex_coord;
      varying vec2 tex_coord_var;

      uniform mat4 transform_matrix;

      void main()
      {

        tex_coord_var = tex_coord;
        gl_Position = vec4(position, 0.0, 1.0);
      }
    )glsl";

const char *fragment_shader = R"glsl(
    #version 100
    precision mediump float;
    varying vec2 tex_coord_var;

    uniform sampler2D tex;

    void main()
    {
        vec4 tex_color = texture2D(tex, tex_coord_var);
        gl_FragColor = vec4(tex_color.r, tex_color.g, tex_color.b, 1.0); 
    }
    )glsl";

static void assertOpenGLError(const std::string &msg)
{
    GLenum error = glGetError();

    if (error != GL_NO_ERROR)
    {
        std::stringstream s;
        s << "OpenGL error 0x" << std::hex << error << " at " << msg;
        throw std::runtime_error(s.str());
    }
}

int main()
{
    int width = 64;
    int height = 64;
    unsigned char *input_image_data = (unsigned char *)malloc(width * height * 4 * sizeof(char));
    unsigned char *frameBufferData = (unsigned char *)malloc(width * height * 4 * sizeof(char));
    unsigned char *test = (unsigned char *)malloc(width * height * 4 * sizeof(char));
    unsigned char *t2 = (unsigned char *)malloc(width * height * 4 * sizeof(char));
    unsigned char *t3 = (unsigned char *)malloc(width * height * 4 * sizeof(char));

    /* 4 color checkers */
    for (int i = 0; i < width * height * 4; i++)
    {
        input_image_data[i] = 1;
    }

    GLuint tex[2];
    GLuint fbo, vbo, ebo, v_shader, f_shader, shader_program;
    GLuint externalTexture;
    GLuint frameBufferTexture;
    EGLDisplay egl_display;
    EGLSurface egl_surface;
    EGLContext egl_context;

    /* EGL context creation */
    EGLConfig egl_config;
    EGLint matching_configs;
    const EGLint config_attrib_list[] = {
        EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
        EGL_NONE};
    const EGLint pbuffer_attrib_list[] = {
        EGL_WIDTH,
        width,
        EGL_HEIGHT,
        height,
        EGL_NONE,
    };
    const EGLint context_attrib_list[] = {
        EGL_CONTEXT_CLIENT_VERSION, 2,
        EGL_NONE};
    egl_display = eglGetDisplay((EGLNativeDisplayType)0);
    eglInitialize(egl_display, 0, 0);
    eglBindAPI(EGL_OPENGL_ES_API);
    eglChooseConfig(egl_display, config_attrib_list, &egl_config, 1, &matching_configs);
#define USE_SURFACE
#if defined USE_SURFACE
    printf("using surface, glEGLImageTargetTexture2DOES will work!\n");
    egl_surface = eglCreatePbufferSurface(egl_display, egl_config, pbuffer_attrib_list);
    egl_context = eglCreateContext(egl_display, egl_config, EGL_NO_CONTEXT, context_attrib_list);
    eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context);
#else
    printf("NOT using surface, glEGLImageTargetTexture2DOES will NOT work\n");
    //egl_surface = eglCreatePbufferSurface (egl_display, egl_config, pbuffer_attrib_list);
    egl_context = eglCreateContext(egl_display, egl_config, EGL_NO_CONTEXT, context_attrib_list);
    eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, egl_context);
#endif

    glGenTextures(1, &externalTexture);
    glGenTextures(1, &frameBufferTexture);
    shader_program = glCreateProgram();

    v_shader = glCreateShader(GL_VERTEX_SHADER);
    f_shader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(v_shader, 1, &vertex_shader, NULL);
    glShaderSource(f_shader, 1, &fragment_shader, NULL);
    glCompileShader(v_shader);
    glCompileShader(f_shader);
    glAttachShader(shader_program, v_shader);
    glAttachShader(shader_program, f_shader);

    GLuint vertex_position, texture_position;
    GLint transform_matrix;

    const GLfloat vertices_textures[20] = {
        //vertices            //positions
        -1.0f, -1.0f, 0.0f, 0.0f, 1.0f,
        1.0f, -1.0f, 0.0f, 1.0f, 1.0f,
        -1.0f, 1.0f, 0.0f, 0.0f, 0.0f,
        1.0f, 1.0f, 0.0f, 1.0f, 0.0f};

    //Fill with data
    for (int i = 0; i < width * height * 4; ++i)
    {
        t2[i] = 112;
    }
    for (int i = 0; i < width * height * 4; ++i)
    {
        t3[i] = 50;
    }

    glLinkProgram(shader_program);
    glUseProgram(shader_program);
    unsigned int vertexBufferObject, vertexArrayObject, TBO, EBO;
    GLint vextexInLocation;
    GLint textureInLocation;
    GLuint vertexbuffer;
    GLuint frameBuffer;
    vextexInLocation = glGetAttribLocation(shader_program, "position");
    textureInLocation = glGetAttribLocation(shader_program, "tex_coord");

    glGenVertexArrays(1, &vertexArrayObject);
    glGenBuffers(1, &vertexBufferObject);

    glBindVertexArray(vertexArrayObject);

    glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices_textures), vertices_textures, GL_STATIC_DRAW);

    glVertexAttribPointer(vextexInLocation, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void *)0);
    glEnableVertexAttribArray(vextexInLocation);

    glVertexAttribPointer(textureInLocation, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void *)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(textureInLocation);

    int texLocation = glGetUniformLocation(shader_program, "tex");

    glGenFramebuffers(1, &frameBuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
    glGenTextures(1, &externalTexture);
    glGenTextures(1, &frameBufferTexture);
    glBindTexture(GL_TEXTURE_2D, frameBufferTexture);
    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_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, t2);

    glUniform1i(texLocation, 0);

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, frameBufferTexture, 0);

    int dmabuf_fd;
    EGLImageKHR egl_image;
    char *virtual_addr;
    
    PFNGLEGLIMAGETARGETTEXTURE2DOESPROC EGLImageTargetTexture2DOES;
    //----------------------Simulates creation of nv egl image decoded from hardware
    
    NvBufferCreateParams input_params;
    input_params.payloadType = NvBufferPayload_SurfArray;
    input_params.width = width;
    input_params.height = height;
    input_params.layout = NvBufferLayout_Pitch;
    input_params.colorFormat = NvBufferColorFormat_ABGR32;
    input_params.nvbuf_tag = NvBufferTag_VIDEO_DEC;

    int ret = NvBufferCreateEx (&dmabuf_fd, &input_params);
    if (ret<0)
        printf("NvBufferCreateEx error!\n");
    //NvBufferCreate(&dmabuf_fd, width, height, NvBufferLayout_BlockLinear, NvBufferColorFormat_ABGR32);
    NvBufferMemMap(dmabuf_fd, 0, NvBufferMem_Read_Write, (void **)&virtual_addr);
    NvBufferMemSyncForCpu(dmabuf_fd, 0, (void **)&virtual_addr);
    for (int i = 0; i < width * height * 4; ++i)
    {
        virtual_addr[i] = input_image_data[i];
    }
    NvBufferMemSyncForDevice(dmabuf_fd, 0, (void **)&virtual_addr);
    egl_image = NvEGLImageFromFd(egl_display, dmabuf_fd);
    EGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)eglGetProcAddress("glEGLImageTargetTexture2DOES");
    /*
    NvBuffer2Raw(dmabuf_fd, 0, width, height, test);
    for (int i = 0; i < 150; ++i)
    {
        printf("%i ", test[i]);
    }
    printf("\n\n");
    */
    //--------------------------------------------------------------------------------

    EGLImageKHR hEglImage;
    hEglImage = NvEGLImageFromFd(egl_display, dmabuf_fd);
 
    glBindTexture(GL_TEXTURE_2D, externalTexture);
    //-----------------------------------------------------
    
    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_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, t3);
    
    //-----------------------------------------------------

    glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES) hEglImage);
    
    glBindVertexArray(vertexArrayObject);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    glReadBuffer(GL_COLOR_ATTACHMENT0);

    glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, frameBufferData);
    printf("frameBufferData:\n");
    for (int i = 0; i < 200; ++i)
    {
        printf("%i ", frameBufferData[i]);
    }
    printf("\n");
   
    glFinish();
    NvDestroyEGLImage(egl_display, egl_image);
    NvBufferMemUnMap(dmabuf_fd, 0, (void **)&virtual_addr);
    NvBufferDestroy(dmabuf_fd);

    glDeleteFramebuffers(1, &fbo);
    glDeleteTextures(2, tex);
    glDeleteBuffers(1, &vbo);
    glDeleteBuffers(1, &ebo);
    glDeleteShader(v_shader);
    glDeleteShader(f_shader);
    glDeleteProgram(shader_program);
    eglDestroyContext(egl_display, egl_context);
    eglDestroySurface(egl_display, egl_surface);
    eglTerminate(egl_display);
    free(input_image_data);

    return 0;
}

Please compile with and without

#define USE_SURFACE

to see the difference.

Compile with

gcc -o lab4 lab4.cpp -lEGL -lGLESv2 -lepoxy -lnvbuf_utils -lstdc++ -L/usr/lib/aarch64-linux-gnu/tegra/ -I/usr/src/nvidia/tegra_multimedia_api/include/

(do sudo apt install -y libepoxy-dev if needed)

hi, did you see my answer? Any news on why a pbuffer surface is needed? This makes it impossible to use with GTK

Hi,
We are checking to reproduce the issue. It can be an issue on r32.2.1 and we will check and evaluate to support it in future releases.

Hi,
Please check
https://www.khronos.org/registry/EGL/sdk/docs/man/html/eglMakeCurrent.xhtml

If ctx is not EGL_NO_CONTEXT, then both draw and read <b>must not be</b> EGL_NO_SURFACE unless context is
a context which supports being bound without read and draw surfaces. In this case the context is made current
without a default framebuffer. The meaning of this is defined by the client API of the supporting context (see
chapter 4 of the OpenGL 3.0 Specification, and the GL_OES_surfaceless_context OpenGL ES extension.).

Without ‘#define USE_SURFACE’, it runs in EGL_NO_CONTEXT and EGL_NO_SURFACE, which is invalid.

Hi,

Please check the spec:

If ctx is not EGL_NO_CONTEXT, then both draw and read must not be EGL_NO_SURFACE unless context is a context which supports being bound without read and draw surfaces. In this case the context is made current without a default framebuffer. The meaning of this is defined by the client API of the supporting context (see chapter 4 of the OpenGL 3.0 Specification, and the GL_OES_surfaceless_context OpenGL ES extension.).
The first time a OpenGL or OpenGL ES context is made current the viewport and scissor dimensions are set to the size of the draw surface (as though glViewport(0,0,w,h) and glScissor(0,0,w,h) were called, where w and h are the width and height of the surface, respectively). However, the viewport and scissor dimensions are not modified when context is subsequently made current. The client is responsible for resetting the viewport and scissor in this case.
The first time context is made current, if it is without a default framebuffer (e.g. both draw and read are EGL_NO_SURFACE ), then the viewport and scissor regions are set as though glViewport(0,0,0,0) and glScissor(0,0,0,0) were called.

If there is no surface set in eglMakeCurrent (but with a context), width and height should be reset before drawing function if you really want to draw something in fragment shader. Thanks

Update the three experiments here:

  1. define USE_SURFACE
    frameBufferData:
    1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255

  2. Not define USE_SURFACE
    frameBufferData:
    112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112 112

  3. Not define USE_SURFACE and add glViewport and glScissor after eglMakeCurrent

#else
    printf("NOT using surface, glEGLImageTargetTexture2DOES will NOT work\n");
    //egl_surface = eglCreatePbufferSurface (egl_display, egl_config, pbuffer_attrib_list);
    egl_context = eglCreateContext(egl_display, egl_config, EGL_NO_CONTEXT, context_attrib_list);
    eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, egl_context);
    glViewport(0, 0, width, height);
    glScissor(0, 0, width, height);
#endif

frameBufferData:
1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255 1 1 1 255