This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TDA4VM: No display while running wayland

Part Number: TDA4VM

Hi Team,

I'm new to TI.

I'm using SDK v 08_02_00_05 (Linux+RTOS).

I'm trying to run a application which loads and display a bmp image using OpenGLES. I'm running application at PC level.

The code is attached below.

/*
 *
gcc m_own_trial.c -o my_own_trial -lwayland-client -lwayland-egl -lEGL -lGLESv2 -lglut -lGL -lGLU 
 */
 
#define EGL_NO_X11

#include <EGL/egl.h>
#include <GLES2/gl2.h>
#include <assert.h>
#include <string.h>
#include <wayland-client.h>
#include <wayland-egl.h>
#include <EGL/eglext.h>
#include <GL/gl.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct wl_display *display = NULL;
struct wl_compositor *compositor = NULL;
struct wl_surface *surface = NULL;
struct wl_shell *shell = NULL;
struct wl_shell_surface *shell_surface = NULL;
struct wl_egl_window *egl_window = NULL;
EGLDisplay egl_display;
EGLContext egl_context;
EGLSurface egl_surface;
GLuint texture;



struct WaylandGlobals {
    struct wl_compositor* compositor;
    struct wl_shell* shell;
};
    
/*
 * Registry callbacks
 */
static void registry_global(void* data, struct wl_registry* registry, uint32_t id, const char* interface, uint32_t version)
{
    struct WaylandGlobals* globals = (struct WaylandGlobals *)data;
    if (strcmp(interface, "wl_compositor") == 0) {
        globals->compositor = wl_registry_bind(registry, id, &wl_compositor_interface, 1);
    } else if (strcmp(interface, "wl_shell") == 0) {
        globals->shell = wl_registry_bind(registry, id, &wl_shell_interface, 1);
    }
}

static const struct wl_registry_listener registry_listener = { registry_global, NULL };

/*
 * Connect to the Wayland display and return the display and the surface
 * output wlDisplay
 * output wlSurface
 */
static void initWaylandDisplay(struct wl_display** wlDisplay, struct wl_surface** wlSurface)
{
    struct WaylandGlobals globals = {0};

    *wlDisplay = wl_display_connect(NULL);
    assert(*wlDisplay != NULL);

    struct wl_registry* registry = wl_display_get_registry(*wlDisplay);
    wl_registry_add_listener(registry, &registry_listener, (void *) &globals);

    wl_display_dispatch(*wlDisplay);
    wl_display_roundtrip(*wlDisplay);
    assert(globals.compositor);
    assert(globals.shell);

    *wlSurface = wl_compositor_create_surface(globals.compositor);
    assert(*wlSurface != NULL);

    struct wl_shell_surface* shellSurface = wl_shell_get_shell_surface(globals.shell, *wlSurface);
    wl_shell_surface_set_toplevel(shellSurface);
}

/*
 * Configure EGL and return necessary resources
 * input nativeDisplay
 * input nativeWindow
 * output eglDisplay
 * output eglSurface
 */
static void initEGLDisplay(EGLNativeDisplayType nativeDisplay, EGLNativeWindowType nativeWindow, EGLDisplay* eglDisplay, EGLSurface* eglSurface)
{
    EGLint number_of_config;
    EGLint config_attribs[] = {
        EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
        EGL_RED_SIZE, 8,
        EGL_GREEN_SIZE, 8,
        EGL_BLUE_SIZE, 8,
        EGL_ALPHA_SIZE, 8,
        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
        EGL_NONE
    };

    static const EGLint context_attribs[] = {
        EGL_CONTEXT_CLIENT_VERSION, 2,
        EGL_NONE
    };

    *eglDisplay = eglGetDisplay(nativeDisplay);
    assert(*eglDisplay != EGL_NO_DISPLAY);

    EGLBoolean initialized = eglInitialize(*eglDisplay, NULL, NULL);
    assert(initialized == EGL_TRUE);

    EGLConfig configs[1];

    eglChooseConfig(*eglDisplay, config_attribs, configs, 1, &number_of_config);
    assert(number_of_config);

    EGLContext eglContext = eglCreateContext(*eglDisplay, configs[0], EGL_NO_CONTEXT, context_attribs);

    *eglSurface = eglCreateWindowSurface(*eglDisplay, configs[0], nativeWindow, NULL);
    assert(*eglSurface != EGL_NO_SURFACE);

    EGLBoolean makeCurrent = eglMakeCurrent(*eglDisplay, *eglSurface, *eglSurface, eglContext);
    assert(makeCurrent == EGL_TRUE);
}

/*
 * Connect Wayland and make EGL
 * input width
 * input height
 * output wlDisplay
 * output eglDisplay
 * output eglSurface
 */
static void initWindow(GLint width, GLint height, struct wl_display** wlDisplay, EGLDisplay* eglDisplay, EGLSurface* eglSurface)
{
    struct wl_surface* wlSurface;
    initWaylandDisplay(wlDisplay, &wlSurface);

    struct wl_egl_window* wlEglWindow = wl_egl_window_create(wlSurface, width, height);
    assert(wlEglWindow != NULL);

    initEGLDisplay((EGLNativeDisplayType) *wlDisplay, (EGLNativeWindowType) wlEglWindow, eglDisplay, eglSurface);
}

/*
 * Return the loaded and compiled shader
 */
GLuint LoadShader(GLenum type, const char* shaderSrc)
{
    GLuint shader = glCreateShader(type);
    assert(shader);

    glShaderSource(shader, 1, &shaderSrc, NULL);
    glCompileShader(shader);

    GLint compiled;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
    assert(compiled);

    return shader;
}

/*
 * Initialize the shaders and return the program object
 */
GLuint initProgramObject()
{
    char vShaderStr[] = "#version 300 es                          \n"
                        "layout(location = 0) in vec4 vPosition;  \n"
                        "void main()                              \n"
                        "{                                        \n"
                        "   gl_Position = vPosition;              \n"
                        "}                                        \n";

    char fShaderStr[] = "#version 300 es                              \n"
                        "precision mediump float;                     \n"
                        "out vec4 fragColor;                          \n"
                        "void main()                                  \n"
                        "{                                            \n"
                        "   fragColor = vec4 ( 1.0, 0.0, 0.0, 1.0 );  \n"
                        "}                                            \n";

    GLuint vertexShader = LoadShader(GL_VERTEX_SHADER, vShaderStr);
    GLuint fragmentShader = LoadShader(GL_FRAGMENT_SHADER, fShaderStr);

    GLuint programObject = glCreateProgram();
    assert(programObject);

    glAttachShader(programObject, vertexShader);
    glAttachShader(programObject, fragmentShader);

    glLinkProgram(programObject);

    GLint linked;
    glGetProgramiv(programObject, GL_LINK_STATUS, &linked);
    assert(linked);

    return programObject;
}



void load_texture(const char *filename) {
    FILE *file = fopen(filename, "rb");
    if (!file) {
        fprintf(stderr, "Failed to open file: %s\n", filename);
        exit(1);
    }

    unsigned char header[54];
    fread(header, sizeof(unsigned char), 54, file);

    int width = *(int*)&header[18];
    int height = *(int*)&header[22];
    int size = 3 * width * height;
    unsigned char *data = (unsigned char *)malloc(size);
    fread(data, sizeof(unsigned char), size, file);
    fclose(file);

    glBindTexture(GL_TEXTURE_2D, texture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, data);
    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);
    
    //fclose(file);
    free(data);
}

void draw() {
    glClear(GL_COLOR_BUFFER_BIT);
glViewport(0, 0, 768, 512);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glBindTexture(GL_TEXTURE_2D, texture);

   /* glBegin(GL_QUADS);
    glTexCoord2f(0, 0); glVertex2f(-1, -1);
    glTexCoord2f(1, 0); glVertex2f(1, -1);
    glTexCoord2f(1, 1); glVertex2f(1, 1);
    glTexCoord2f(0, 1); glVertex2f(-1, 1);
    glEnd();*/
    
     // Specify the texture coordinates and vertices for a quad
    GLfloat texCoords[] = {0.0f, 0.0f,
                           1.0f, 0.0f,
                           1.0f, 1.0f,
                           0.0f, 1.0f};

    GLfloat vertices[] = {-1.0f, -1.0f,
                           1.0f, -1.0f,
                           1.0f, 1.0f,
                           -1.0f, 1.0f};

    // Draw the quad
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
    glVertexPointer(2, GL_FLOAT, 0, vertices);
    glDrawArrays(GL_QUADS, 0, 4);

    // Disable texture coordinates
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);

    // Swap the buffers
    eglSwapBuffers(egl_display, egl_surface);
    //glFlush();
}

/*
 * Draw a triangle
 */
/*void draw(GLuint programObject, GLint width, GLint height)
{
    GLfloat vVertices[] = { -0.5f, -0.5f, 0.0f,
        0.0f,  0.5f, 0.0f,
        0.5f, -0.5f, 0.0f };

    glViewport(0, 0, width, height);
    glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    glUseProgram(programObject);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vVertices);
    glEnableVertexAttribArray(0);
    glDrawArrays(GL_TRIANGLES, 0, 3);
}*/

int main(int argc, char** argv)
{
    int width = 768;
    int height = 512;
    if (argc < 2) {
            fprintf(stderr, "Usage: %s <image_file>\n", argv[0]);
            return 1;
    }
    struct wl_display* wlDisplay;
    EGLDisplay eglDisplay;		
    EGLSurface eglSurface;
    printf("1\n");
    initWindow(width, height, &wlDisplay, &eglDisplay, &eglSurface);
    printf("2\n");
    GLuint programObject = initProgramObject();
    printf("3\n");
    assert(programObject);
    printf("4\n");
    load_texture(argv[1]);
    printf("5\n");
    //draw();
    //draw(programObject, width, height);
    eglSwapBuffers(eglDisplay, eglSurface);
    printf("6\n");
printf("display:%d\n",wl_display_dispatch(wlDisplay));
    while (wl_display_dispatch(wlDisplay) != -1) {
        draw();
    printf("7\n");
    }

    glDeleteProgram(programObject);
    printf("8\n");
    wl_display_disconnect(wlDisplay);

    return 0;
}


While running the code, it is working fine without errors but no output on display. please find the logs and output image attached below for reference.

prakash@kli:~/ti-processor-sdk-rtos-j721e-evm-08_02_00_05/vision_apps/apps/dl_demos/OpenGL_Task/Using_GLUT$ gcc m_own_trial.c -o my_own_trial -lwayland-client -lwayland-egl -lEGL -lGLESv2 -lglut -lGL -lGLU 
prakash@kli:~/ti-processor-sdk-rtos-j721e-evm-08_02_00_05/vision_apps/apps/dl_demos/OpenGL_Task/Using_GLUT$ ./my_own_trial image.bmp 
1
2
3
4
5
6
display:3
7
7
Killed
prakash@kli:~/ti-processor-sdk-rtos-j721e-evm-08_02_00_05/vision_apps/apps/dl_demos/OpenGL_Task/Using_GLUT$ 

As shown in image no output is able to visualise on display.

Kindly let me know how to resolve this, I have all dependencies installed in system and running application using wayland support.

Thanks,

Chaitanya Prakash Uppala

  • Hello,

    What does your PC Setup look like?

    For example, I'm running Ubuntu 22.04, and my current windowing system is X11. However, I can switch to a wayland session if I need to run wayland applications. Or, I can also launch weston under X11 to run wayland applications in that context.

    Is that how you are trying to run your application?

    Regards,

    Erick

  • I'm using Ubuntu 20.04

    I have switch to Ubuntu on Wayland for running the application.

    Is that how you are trying to run your application?

    Yes, exactly. 

  • Hello,

    Understood.

    I tried running it as well, it seems to get stuck for some reason, and I'm not sure if it's the sequence of operations.

    Can you please compare to these examples:

    https://github.com/joone/opengl-wayland

    I tried running these on my system and they run fine. Perhaps there is something missing.

    Regards,

    Erick

  • Hi Erick,

    I tried running these on my system and they run fine

    Even I have tried at my end, these are running fine.

    Also I have taken one open sorce code which draws a triangle using wayland, and ran in same manner as I did for above code and it ran and showed display. But not sure why displaying bmp image( the above code) code is not showing display while running.

    I have tried with modifying code, but still display is not up. The code is attached for reference.

    
    
    
    
    #define EGL_NO_X11
    
    #include <EGL/egl.h>
    #include <GLES2/gl2.h>
    #include <assert.h>
    #include <string.h>
    #include <wayland-client.h>
    #include <wayland-egl.h>
    #include <EGL/eglext.h>
    
    #include <stdio.h>
    #include <stdlib.h>
    
    #define WINDOW_WIDTH 768
    #define WINDOW_HEIGHT 512
    
    EGLDisplay egl_display;
    EGLSurface egl_surface;
    EGLContext egl_context;
    GLuint program_object;
    GLuint texture;
    struct wl_compositor *compositor = NULL;
    
    static void initEGL(EGLNativeWindowType native_window) {
        EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
        EGLConfig config;
        EGLint num_configs;
        EGLint major, minor;
    
        egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
        eglInitialize(egl_display, &major, &minor);
        eglBindAPI(EGL_OPENGL_ES_API);
    
        EGLint attrib_list[] = {
            EGL_RED_SIZE, 8,
            EGL_GREEN_SIZE, 8,
            EGL_BLUE_SIZE, 8,
            EGL_ALPHA_SIZE, 8,
            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
            EGL_NONE};
    
        eglChooseConfig(egl_display, attrib_list, &config, 1, &num_configs);
        egl_surface = eglCreateWindowSurface(egl_display, config, native_window, NULL);
        egl_context = eglCreateContext(egl_display, config, EGL_NO_CONTEXT, context_attribs);
    
        eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context);
    }
    static void registry_global(void* data, struct wl_registry* registry, uint32_t id, const char* interface, uint32_t version)
    {
        if (strcmp(interface, "wl_compositor") == 0) {
            compositor = wl_registry_bind(registry, id, &wl_compositor_interface, 1);
        }
    }
    void load_texture(const char *filename) {
        // Load the texture here
         FILE *file = fopen(filename, "rb");
        if (!file) {
            fprintf(stderr, "Failed to open file: %s\n", filename);
            exit(1);
        }
    
        unsigned char header[54];
        fread(header, sizeof(unsigned char), 54, file);
    
        int width = *(int*)&header[18];
        int height = *(int*)&header[22];
        int size = 3 * width * height;
        unsigned char *data = (unsigned char *)malloc(size);
        fread(data, sizeof(unsigned char), size, file);
        fclose(file);
    
        glBindTexture(GL_TEXTURE_2D, texture);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
        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);
        
        //fclose(file);
        free(data);
    }
    GLuint LoadShader(GLenum type, const char* shaderSrc)
    {
        GLuint shader = glCreateShader(type);
        assert(shader);
    
        glShaderSource(shader, 1, &shaderSrc, NULL);
        glCompileShader(shader);
    
        GLint compiled;
        glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
        assert(compiled);
    
        return shader;
    }
    GLuint initProgramObject()
    {
        char vShaderStr[] = "#version 300 es                          \n"
                            "layout(location = 0) in vec4 vPosition;  \n"
                            "void main()                              \n"
                            "{                                        \n"
                            "   gl_Position = vPosition;              \n"
                            "}                                        \n";
    
        char fShaderStr[] = "#version 300 es                              \n"
                            "precision mediump float;                     \n"
                            "out vec4 fragColor;                          \n"
                            "void main()                                  \n"
                            "{                                            \n"
                            "   fragColor = vec4 ( 1.0, 0.0, 0.0, 1.0 );  \n"
                            "}                                            \n";
    
        GLuint vertexShader = LoadShader(GL_VERTEX_SHADER, vShaderStr);
        GLuint fragmentShader = LoadShader(GL_FRAGMENT_SHADER, fShaderStr);
    
        GLuint programObject = glCreateProgram();
        assert(programObject);
    
        glAttachShader(programObject, vertexShader);
        glAttachShader(programObject, fragmentShader);
    
        glLinkProgram(programObject);
    
        GLint linked;
        glGetProgramiv(programObject, GL_LINK_STATUS, &linked);
        assert(linked);
    
        return programObject;
    }
    static void draw() {
        glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
    
        // Draw your OpenGL content here
        glViewport(0, 0, 768, 512);
    
        // Bind the texture
        glBindTexture(GL_TEXTURE_2D, texture);
    
        // Specify the texture coordinates and vertices for a quad
        GLfloat texCoords[] = {0.0f, 0.0f,
                               1.0f, 0.0f,
                               1.0f, 1.0f,
                               0.0f, 1.0f};
    
        GLfloat vertices[] = {-1.0f, -1.0f,
                               1.0f, -1.0f,
                               1.0f, 1.0f,
                               -1.0f, 1.0f};
    
        // Enable vertex and texture coordinate arrays
        glEnableVertexAttribArray(0);
        glEnableVertexAttribArray(1);
    
        // Specify the texture coordinates
        glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, texCoords);
        // Specify the vertices
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, vertices);
    
        // Draw the quad
        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
    
        // Disable vertex and texture coordinate arrays
        glDisableVertexAttribArray(0);
        glDisableVertexAttribArray(1);
    
        // Swap the buffers
        eglSwapBuffers(egl_display, egl_surface);
    }
    static const struct wl_registry_listener registry_listener = { registry_global, NULL };
    int main(int argc, char **argv) {
        struct wl_display *display = wl_display_connect(NULL);
        assert(display);
    
        struct wl_registry *registry = wl_display_get_registry(display);
        wl_registry_add_listener(registry, &registry_listener, NULL);
    
        wl_display_dispatch(display);
        wl_display_roundtrip(display);
    
        assert(compositor);
        //assert(shell);
    
        struct wl_surface *surface = wl_compositor_create_surface(compositor);
        assert(surface);
    
        struct wl_egl_window *egl_window = wl_egl_window_create(surface, WINDOW_WIDTH, WINDOW_HEIGHT);
        assert(egl_window);
    
        initEGL((EGLNativeWindowType)egl_window);
    
        program_object = initProgramObject();
    
        // Load texture and other initialization tasks can be added here
        printf("Loading texture...\n");
        load_texture(argv[1]);
        while (1) {
            draw();
            printf("after draw\n");
            /*int ret = wl_display_dispatch(display);
            printf("ret value %d\n",wl_display_dispatch(display));
            if (ret == -1)
                break; // Error occurred
            */
            
        }
    
        eglDestroySurface(egl_display, egl_surface);
        eglDestroyContext(egl_display, egl_context);
        eglTerminate(egl_display);
    
        wl_egl_window_destroy(egl_window);
        wl_surface_destroy(surface);
        wl_registry_destroy(registry);
        wl_display_disconnect(display);
    
        return 0;
    }
    
    

    Log is as shown below

    prakash@kli:~/ti-processor-sdk-rtos-j721e-evm-08_02_00_05/vision_apps/apps/dl_demos/OpenGL_Task/Using_GLUT$gcc my_trial_8.c -o my_trial_8 -lwayland-client -lwayland-egl -lEGL -lGLESv2 -lGL
    prakash@kli:~/ti-processor-sdk-rtos-j721e-evm-08_02_00_05/vision_apps/apps/dl_demos/OpenGL_Task/Using_GLUT$ ./my_trial_8 image.bmp 
    Loading texture...
    after draw
    after draw
    after draw
    after draw
    after draw
    after draw
    after draw
    after draw
    after draw....(infinite after draw prints)

    In the main function when enabled

    "int ret = wl_display_dispatch(display);
    if (ret == -1)
    break;", this part inside while it is getting stuck.

    Regards,

    Chaitanya Ptrakash Uppala

  • Chaitanya,

    This seems to be a program error as opposed to an error in our GPU driver (since you are running on your PC).

    One question I have is why you are running on Wayland Windowing system but are planning to use the RTOS+Linux setup. In the Linux+RTOS setup, the display is removed (dss) in the device tree, hence there is no windowing system. So your experiment will not work when you run on the target.

    Regards,

    Erick

  • Hello Erick,

    I need to pass input image buffer to GPU and render the image on display.

    At the end I need to integrate the same logic in one of the application in SDK 08_02_00_05 (Linux+RTOS). For that, I'm developing a standalone application with same functionality and running at PC level. So, once I get output at PC level, I can run the same binary on target.

    I have ran simple_triangle program which draws a triangle in the same manner, ran as a standalone then copied executable to target and ran on target, it worked. Following is the query regarding that : https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1214641/faq-tda4vm-sample-wayland-application-of-opengl-to-run-on-ti-board/4609640?tisearch=e2e-sitesearch&keymatch=chaitanya%2520Prakash%2520uppala#4609640

    I'm trying to do in the same way, but the use case is different. Here it is rendering bmp image.

    Regards,

    Chaitanya Prakash Uppala

  • At the end I need to integrate the same logic in one of the application in SDK 08_02_00_05 (Linux+RTOS). For that, I'm developing a standalone application with same functionality and running at PC level. So, once I get output at PC level, I can run the same binary on target.

    It does not seem you are running the Linux+RTOS then, as you have native Linux display output.

    Regardless, if what you want to run is an OpenGL application on the wayland compositor, that reads a bmp and outputs it to the display, we can work on an example for you. It won't be ready this week. In the meantime, I suggest you to try and debug your application as something is wrong since it can't run on a PC.

    Regards,

    Erick

  • we can work on an example for you. It won't be ready this week.

    That's great. Thank you so much. 

    I suggest you to try and debug your application as something is wrong since it can't run on a PC.

    Sure.

    I have switched to run the same task inside kernel, I have generated a custom kernel inside TIOVX. and added gl related code inside process function. TIOVX build successfully. 

    Guide me with the procedure I can take for loading a image and displaying it inside vis_apps application, while running on target.

     

    Regards,

    Chaitanya Prakash Uppala

  • Chaitanya,

    The code may build, but there will be un-met runtime dependencies when you try to launch it. Because you are running in an RTOS+Linux environment (Vision Apps), the display has been disabled. So you cannot intialize weston as it won't be able to find the display.

    Using the GPU in this scenario is usually for processing camera data or supporting the vision pipeline. If you want to use a windowing system from Linux, you won't be able to because the DSS is owned by the R5 OpenVX display node.

    I'm not sure it will be fruitful to build this wayland application as it won't be able to run in your target environment. Can you please give me more detail as to your what your final application will look like?

    Regards,

    Erick

  • Hi Erick,

    I have a query similar to this thread.

    I have a working OpenGL PC application which takes an input image of type UINT8 and generate top view based on LUT. So this you can conider as a node which generates a top view(UINT8).

    I want to insert this as a node in an application on TDA4VM. My SDK is 08_02_00_05 (Linux+RTOS).

    The approach which I am following to implement the same:
    1) Created a tiovx node on A72 with input/output type VX_DF_IMAGE_U8
    2) In the process function of this new node I am trying to process all OpenGL operations. Reading the image as a texture. I have vertex and fragment shader processing also.
    3) Reading final OpenGL output from framebuffer using glReadPixel API(same happening in app_srv_camera demo) and then passing this output to Mosaic to process further for display. As Mosaic supports UINT8 data type so it should display the image no matter from where the image is coming GPU or any other hardware.

    I have taken app_srv_camera demo application as reference as it is the only demo which has OpenGL operations. The only difference is my kernel is in tiovx and app_srv_camera is in vision_apps.


    Problem:
    1) I am able to build and run the application but it seems some of the OpenGL APIs are not working i.e. no change in the output, same as input. Even if I try to flip the image but output is same as input.
    2) Is my approch stated above is correct? If no, please could you suggest correct approch to achieve that.

    Please provide me a proper process to implement the same as going forward more complex OpenGL nodes will be integrated in the application. Need to be very sure about the process.

    Regards,
    Harib

  • Harib,

    1) I am able to build and run the application but it seems some of the OpenGL APIs are not working i.e. no change in the output, same as input. Even if I try to flip the image but output is same as input.

    Have you checked for glErrors?

    2) Is my approch stated above is correct? If no, please could you suggest correct approch to achieve that.

    Your approach seems correct. I don't think glReadPixel is the most optimal way to handle this but it work.

    Regards,

    Erick

  • Hi Erick,

    I have a working OpenGL code with off-screen rendering on PC. It's just loading a RGB texture, inverting texture in fragment shader and final output I am reading from the frame buffer.
    Same code when integrated in tiovx custom kernel it is not working as expected. I am getting blank dark green image(glClearColor). Please have a look on the code below:
    	glSrvParams = tivxMemAlloc(sizeof(tivxGlSrvParams), TIVX_MEM_EXTERNAL);
        if(NULL != glSrvParams)
        {
            memset(glSrvParams, 0, sizeof(tivxGlSrvParams));
        }
        else
        {
            printf("GL SRV: ERROR: Couldn't allocate memory! %d\n", VX_ERROR_NO_MEMORY);
            status = VX_ERROR_NO_MEMORY;
        }
    
        glSrvParams->eglWindowObj = appEglWindowOpen();
        if (NULL != glSrvParams->eglWindowObj)
        {
            printf("EGL window created successfully\n");
        }
        else
        {
            printf("EGL window creation failed\n");
        }
    
        GLenum render_mode = GL_TRIANGLES;
    
        float vertices[] = {
        // positions          // colors          
        -1.0, -1.0, 0.0,    0.0,       0.0,      
         1.0, -1.0, 0.0,    1.0/2.0,   0.0,      
        -1.0,  1.0, 0.0,    0.0,       1.0/2.0,  
         1.0,  1.0, 0.0,    1.0/2.0,   1.0/2.0   
        };
        unsigned int indices[] = {  
            0, 1, 2,
            1, 2, 3
        };
    
        GLuint shaderProgram = Build_Shaders();
    
        GLuint texture;
        glGenTextures(1, &texture);
        GL_ERROR_CHECK(glGenTextures);
        glBindTexture(GL_TEXTURE_2D, texture);
        GL_ERROR_CHECK(glBindTexture);
    
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    
        unsigned char *inputImg;
        int width, height, nrChannels;
    
        stbi_set_flip_vertically_on_load(GL_TRUE);
        inputImg = stbi_load(INPUT_IMAGE, &width, &height, &nrChannels, STBI_rgb);
        printf("width height channels %d, %d, %d\n", width, height, nrChannels);
    
        glPixelStorei(GL_UNPACK_ALIGNMENT,1);
        GL_ERROR_CHECK(glPixelStorei);
        if (inputImg)
        {
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, inputImg);
            GL_ERROR_CHECK(glTexImage2D);
        }
        else
        {
            printf("Failed to load texture\n");
        }
        stbi_image_free(inputImg);
    
        glUseProgram(shaderProgram);
        GL_ERROR_CHECK(glUseProgram);
        GLuint aPosAttribLoc = glGetAttribLocation(shaderProgram, "aPos");
        GL_ERROR_CHECK(glGetAttribLocation);
    
        GLuint texAttribLoc = glGetAttribLocation(shaderProgram, "texCord");
        GL_ERROR_CHECK(glGetAttribLocation);
    
        GLuint samplerLocation0 = glGetUniformLocation(shaderProgram, "img_texture");
    	glUniform1i(samplerLocation0, 0);
    	GL_ERROR_CHECK(glUniform1i);
    
        GLuint bufs[2];
        glGenBuffers(2, bufs);
        GL_ERROR_CHECK(glGenBuffers);
    
        glBindBuffer(GL_ARRAY_BUFFER, bufs[0]);
        GL_ERROR_CHECK(glBindBuffer);
    
        glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
        GL_ERROR_CHECK(glBufferData);
    
        glVertexAttribPointer(aPosAttribLoc, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
        GL_ERROR_CHECK(glVertexAttribPointer);
        glEnableVertexAttribArray(aPosAttribLoc);
        GL_ERROR_CHECK(glEnableVertexAttribArray);
    
        glVertexAttribPointer(texAttribLoc, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3*sizeof(float)));
        GL_ERROR_CHECK(glVertexAttribPointer);
        glEnableVertexAttribArray(aPosAttribLoc);
        GL_ERROR_CHECK(glEnableVertexAttribArray);
    
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufs[1]);
        GL_ERROR_CHECK(glBindBuffer);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
        GL_ERROR_CHECK(glBufferData);
    
    
        GLuint framebuffer = 0;
        glGenFramebuffers(1, &framebuffer);
        GL_ERROR_CHECK(glGenFramebuffers);
        glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
        GL_ERROR_CHECK(glBindFramebuffer);
    
        GLuint textureColorbuffer;
        glGenTextures(1, &textureColorbuffer);
        glBindTexture(GL_TEXTURE_2D, textureColorbuffer);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 768, 512, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
    
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
                
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureColorbuffer, 0);
        GL_ERROR_CHECK(glFramebufferTexture2D);
        GLenum fbstatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
        if (fbstatus != GL_FRAMEBUFFER_COMPLETE)
        {
            printf("EGL: ERROR: Frambuffer complete check failed 0x%x\n", fbstatus);
        }
    
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
        GL_ERROR_CHECK(glBindFramebuffer);
    
        glUseProgram(shaderProgram);
        GL_ERROR_CHECK(glUseProgram);
    
        glClear(GL_COLOR_BUFFER_BIT);
    
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, texture);
    	glUniform1i(samplerLocation0, 0);
    
        glDrawElements(render_mode, 6, GL_UNSIGNED_INT, 0);
        GL_ERROR_CHECK(glDrawElements);
    
        glFinish();
        GL_ERROR_CHECK("glFinish");
        glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
    
        int data_size = OUTPUT_IMAGE_WIDTH * OUTPUT_IMAGE_HEIGHT * 3;
        unsigned char  *pixels = (unsigned char *)malloc(data_size * sizeof(unsigned char));
    
        glReadPixels(0, 0, OUTPUT_IMAGE_WIDTH, OUTPUT_IMAGE_HEIGHT, GL_RGB, GL_UNSIGNED_BYTE, pixels);
        GL_ERROR_CHECK("glReadPixels");
    
        stbi_flip_vertically_on_write(GL_TRUE);
        stbi_write_bmp( OUPUT_IMAGE_PATH, OUTPUT_IMAGE_WIDTH, OUTPUT_IMAGE_HEIGHT, 3, pixels );
    
        free(pixels);
        glDeleteTextures(1, &textureColorbuffer);
        glDeleteTextures(1, &texture);
        glDeleteBuffers(2, bufs);
        glDeleteProgram(shaderProgram);
        glDeleteFramebuffers(1, &framebuffer);

    Important points:
    1) The only difference with PC working code is that in PC code window is created using GLFW, whereas in tiovx, window is created using appEglWindowOpen(ref taken from app_srv_camera application).
    2) I don't have the definition of appEglWindowOpen() explicitly, I am just calling it and linking all srv_camera_app directories paths. I am assuming it must be a standard function which creates a window for OpenGL context. 
    3) There is no OpenGL error also, everything seems to be working fine as below:
    GL Error = 0 for "glAttachShader"
    GL Error = 0 for "glAttachShader"
    GL Error = 0 for glGenTextures
    GL Error = 0 for glBindTexture
    GL Error = 0 for glPixelStorei
    GL Error = 0 for glTexImage2D
    GL Error = 0 for glUseProgram
    GL Error = 0 for glGetAttribLocation
    GL Error = 0 for glGetAttribLocation
    GL Error = 0 for glUniform1i
    GL Error = 0 for glGenBuffers
    GL Error = 0 for glBindBuffer
    GL Error = 0 for glBufferData
    GL Error = 0 for glVertexAttribPointer
    GL Error = 0 for glEnableVertexAttribArray
    GL Error = 0 for glVertexAttribPointer
    GL Error = 0 for glEnableVertexAttribArray
    GL Error = 0 for glBindBuffer
    GL Error = 0 for glBufferData
    GL Error = 0 for glGenFramebuffers
    GL Error = 0 for glBindFramebuffer
    GL Error = 0 for glFramebufferTexture2D
    GL Error = 0 for glBindFramebuffer
    GL Error = 0 for glUseProgram
    GL Error = 0 for glDrawElements
    GL Error = 0 for "glFinish"
    GL Error = 0 for "glReadPixels"
    4) I am not using dmaBuf.

    Am I missing something? Please let me know, I am kind of stuck at this point.

    My target is to implement a tiovx node which uses OpenGL to do off-screen rendering and passes the final output to next node.
    Regards,
    Harib
  • Harib,

    Can you please replace glFinish() with glFlush() and let me know that if the behavior changes? It seems you are rendering into a framebuffer that you created, which should be OK.

    Thanks,

    Erick

  • Hi Erick,

    I am still getting blank output even after replacing glFinish() with glFlush(). 

    Please let me know how to resolve the above mentioned issue.

    The only part which is unclear to me right now is appEglWindowOpen(). As I mentioned above I don't have its definition explicitly just using the function. Could this be the reason?

    Regards,

    Harib

  • Harib,

    The only part which is unclear to me right now is appEglWindowOpen(). As I mentioned above I don't have its definition explicitly just using the function. Could this be the reason?

    appEglWindowOpen() initializes EGL and chooses a surfaceless context:

    186 void *appEglWindowOpen()
    187 {
    188     const char *egl_platform_extensions;
    189     EGLint num_configs;
    190     EGLint majorVersion;
    191     EGLint minorVersion;
    192     int32_t ret = 0;
    193     uint32_t count;
    194 
    195     const EGLint attribs[] = {
    196        EGL_RED_SIZE, 8,
    197        EGL_GREEN_SIZE, 8,
    198        EGL_BLUE_SIZE, 8,
    199        EGL_ALPHA_SIZE, 8,
    200        EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
    201        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR,
    202        EGL_DEPTH_SIZE, 16,
    203        EGL_NONE
    204     };
    205 
    206     EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE };
    207 
    208     app_egl_obj_t *obj;
    209 
    210     obj = malloc(sizeof(app_egl_obj_t));
    211     if(obj==NULL)
    212     {
    213         goto goto_error;
    214     }
    215     obj->drm_fd = -1;
    216     obj->gbm_dev = NULL;
    217     obj->gbm_surface = NULL;
    218     obj->surface = EGL_NO_SURFACE;
    219 
    220     for(count=0; count < APP_EGL_MAX_TEXTURES; count++)
    221     {
    222         appEglWindowResetTex(&obj->tex[count]);
    223     }
    224     for(count=0; count < APP_EGL_MAX_RENDER_TEXTURES; count++)
    225     {
    226         appEglWindowResetTex(&obj->texRender[count]);
    227     }
    ...
    236     egl_platform_extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
    237 
    238     if (has_extension(egl_platform_extensions, "EGL_MESA_platform_surfaceless"))
    239     {
    240         obj->display = obj->get_platform_display(EGL_PLATFORM_SURFACELESS_MESA,
    241                 EGL_DEFAULT_DISPLAY, NULL);
    242     }
    ...
    285     ret = eglInitialize(obj->display, &majorVersion, &minorVersion);
    286     appEglCheckEglError("eglInitialize", ret);
    287     if (ret != EGL_TRUE)
    288     {
    289         printf("EGL: ERROR: eglInitialize() failed !!!\n");
    290         goto terminate_display;
    291     }
    292     printf("EGL: version %d.%d\n", majorVersion, minorVersion);
    293 
    294     if (!eglBindAPI(EGL_OPENGL_ES_API))
    295     {
    296         printf("EGL: ERROR: eglBindAPI(EGL_OPENGL_ES_API) failed !!!\n");
    297         goto terminate_display;
    298     }
    299 
    300     if (obj->gbm_surface)
    301     {
    302         if (!eglChooseConfig(obj->display, attribs, &obj->config, 1, &num_configs))
    303         {
    304             printf("EGL: eglChooseConfig() failed. Couldn't get an EGL visual config !!!\n");
    305             goto terminate_display;
    306         }
    307 
    308         obj->context = eglCreateContext(obj->display, obj->config, EGL_NO_CONTEXT, context_attribs);
    309     }
    310     else
    311     {
    312         /* with surfaceless platform, there is no need for config */
    313         obj->context = eglCreateContext(obj->display, EGL_NO_CONFIG_KHR,
    314                 EGL_NO_CONTEXT, context_attribs);
    315     }
    316     appEglCheckEglError("eglCreateContext", EGL_TRUE);
    317     if (obj->context == EGL_NO_CONTEXT)
    318     {
    319         printf("EGL: ERROR: eglCreateContext() failed !!!\n");
    320         goto terminate_display;
    321     }
    ...
    

    It might do a bit more than you need, but at the end if it does not return an error code it should have initialized an EGL_NO_CONTEXT. And the rest of your functions are not returning error codes, so they should be working in the background.

    The fact that glClearColor is affecting the output is a good sign, now we only need to figure out why your Draw call is not rendering onto the output.

    Can you add a glViewport() command, and set it to the size of your output?

    Regards,

    Erick

  • Hi Erick,

    Thanks for your reply.

    I added glViewPort(0,0,768,512). The output color got changed but it's still a blank color. Light Black color different from glClearColor.

    appEglWindowOpen() initializes EGL and chooses a surfaceless context:

    Yes I seen appEglWindowOpen() function inside app_gl_egl_utils_linux.c file but when I put printf inside this function, I didn't get any printfs so I got confused which appEglWindowOpen() it is calling.

    Now I extracted complete appEglWindowOpen() from app_gl_egl_utils_linux.c file and placed it inside my tiovx ..kernel_target.c file. This didn't make any difference in output.

    Questions:

    1) Do I need to use function appEglWindowCreateIMG() given in app_gl_egl_utils_linux.c file to create egl image? Because right now I am not creating any egl image, I am just creating a texture.

    I don't have much experience with EGL. I know OpenGL. I implemented the application on PC and it is working but having problem on TDA4VM board side.

    Regards,

    Harib

  • Harib,

    Perhaps we will need to do an experiment with the context that is used in Vision Apps. The GBM path should not be taken, normally the other path is taken.

    1) Do I need to use function appEglWindowCreateIMG() given in app_gl_egl_utils_linux.c file to create egl image? Because right now I am not creating any egl image, I am just creating a texture.

    Right, you aren't going to use EGL Images, so I don't think you need this specific initialization. But EGL requires a display surface to initialize, and without a surface perhaps we don't need EGL at all. We'll need to check this point if OpenGL is simply going to render off-screen on generated framebuffers from OpenGLES.

    I don't have much experience with EGL. I know OpenGL. I implemented the application on PC and it is working but having problem on TDA4VM board side.

    Right, I've noticed discrepancy, especially in implementations of OpenGL drivers from NVIDIA to others. But we would need to see if there's a solution feasible given our constraints in the system.

    Let us try to create a standalone app that does not integrate with the vision apps framework first, and then work on it's integration.

    Regards,

    Erick

  • Hi Erick,

    Thank you so much for your replies.

    Now the glDrawElement problem is resolved. I am able to dump proper output using glReadPixel(). I wrote another node from scratch and it worked. Didn't check why previous one was not working.

    Now I am having some doubts:
    1) Why GPU utlization on screen is always zero. No matter how much complex calculations I am doing inside vertex/fragment shader, it is always 0? Any idea?
    2) As I explained I am copying an RGB image to GPU buffer as texture, doing operations and loading the final output image using glReadPixel() API. Final output is given to Mosaic node. This is happening for all frames. glReadPixel() alone is taking ~20ms on TDA4VM board. Is there any alternative faster API which I can use? Please let me know how to avoid glReadPixel to achieve better performance.

    Regards,
    Harib

  • Harib,

    1) Why GPU utlization on screen is always zero. No matter how much complex calculations I am doing inside vertex/fragment shader, it is always 0? Any idea?

    This is interesting, the GPU utilization is calculated based on a debug kernel entry in /sys/kernel/debug/pvr/status. You can continuously "cat" that file to see the contents. I'm thinking that without explicit frame synchronization points or eglSwapBuffer calls, it might not get updated. Can you make sure you have eglSwapBuffers and glFlush in your code and see if that changes the loading behaviour? If not we can also check with the PVRTune tool.

    2) As I explained I am copying an RGB image to GPU buffer as texture, doing operations and loading the final output image using glReadPixel() API. Final output is given to Mosaic node. This is happening for all frames. glReadPixel() alone is taking ~20ms on TDA4VM board. Is there any alternative faster API which I can use? Please let me know how to avoid glReadPixel to achieve better performance.

    Yes, the glReadPixel is quite long. The better way to do this is with a dma-buf, that way the GPU will have written directly into the buffer you will be using later and we achieve a zero-copy buffer exchange in the pipeline. Would this be an option for you?

    Regards,

    Erick