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.

PROCESSOR-SDK-AM335X: Memory leak when use wayland-egl

Part Number: PROCESSOR-SDK-AM335X

Hi,

we are seeing memory leak when a Wayland client process using wayland-egl is executed.

For example, weston-simple-egl, /usr/bin/SGX/demos/Wayland/OGLES2ChameleonMan.

Valgrind shows us these memory leak as below,

==1206== 8 bytes in 1 blocks are definitely lost in loss record 1 of 7
==1206== at 0x4847988: malloc (vg_replace_malloc.c:299)
==1206== by 0x4D1552B: PVRSRVCreateAppHintState (in /usr/lib/libsrv_um.so.1.17.4948957)
==1206==
==1206== 12 bytes in 1 blocks are indirectly lost in loss record 2 of 7
==1206== at 0x4847988: malloc (vg_replace_malloc.c:299)
==1206== by 0x4948FE1: wl_display_create_queue (in /usr/lib/libwayland-client.so.0.3.0)
==1206==
==1206== 32 bytes in 1 blocks are still reachable in loss record 3 of 7
==1206== at 0x4847988: malloc (vg_replace_malloc.c:299)
==1206== by 0x4D16C73: PVRSRVCreateDeferredTask (in /usr/lib/libsrv_um.so.1.17.4948957)
==1206==
==1206== 40 bytes in 1 blocks are definitely lost in loss record 4 of 7
==1206== at 0x484A5A8: calloc (vg_replace_malloc.c:752)
==1206== by 0x4949C33: wl_proxy_create_wrapper (in /usr/lib/libwayland-client.so.0.3.0)
==1206==
==1206== 52 (40 direct, 12 indirect) bytes in 1 blocks are definitely lost in loss record 5 of 7
==1206== at 0x484A5A8: calloc (vg_replace_malloc.c:752)
==1206== by 0x4948E53: ??? (in /usr/lib/libwayland-client.so.0.3.0)
==1206==
==1206== 120 bytes in 3 blocks are still reachable in loss record 6 of 7
==1206== at 0x484A5A8: calloc (vg_replace_malloc.c:752)
==1206== by 0x4948E53: ??? (in /usr/lib/libwayland-client.so.0.3.0)
==1206==
==1206== 2,076 bytes in 1 blocks are still reachable in loss record 7 of 7
==1206== at 0x484A5A8: calloc (vg_replace_malloc.c:752)
==1206== by 0x4E01675: drmHashCreate (in /usr/lib/libdrm.so.2.4.0)
==1206==
==1206== LEAK SUMMARY:
==1206== definitely lost: 88 bytes in 3 blocks
==1206== indirectly lost: 12 bytes in 1 blocks
==1206== possibly lost: 0 bytes in 0 blocks
==1206== still reachable: 2,228 bytes in 5 blocks
==1206== suppressed: 0 bytes in 0 blocks

We have attached the full result of valgrind.

weston-simple-egl-valgrind-20210312-am335x-evm.log

OGLES2-ChameleonMan-valgrind-20210312-am335x-evm.log

Do you have any idea to solve this?

Hardware:

am335x-evm

Software:

PROCESSOR-SDK-LINUX-AM335X  06_01_00_08.

Thank you.

  • Hello,

    I am wondering if this is only specific to Wayland and did you try the examples under the "/usr/bin/SGX/demos/Raw"? I am seeing similar issues being reported in the community as well.

    1. https://gitlab.gnome.org/GNOME/gimp/-/issues/4092
    2
    https://gitlab.freedesktop.org/wayland/weston/-/merge_requests/250

    Regards,
    Krunal

  • Hi, Krunal-san.

    I tried this examples under the "/usr/bin/SGX/demos/Raw" and the memory leakage didn't happened.

    I also tried the patch in the 2nd issue you showed kindly, however It had no effect on this problem.

    Is there any other way to solve?

    Regards,

    Takayuki

  • Hello Takayuki,

    Based on your experiment and the online posts, the issue seems to be related to Wayland. TI does not own, support and maintain the Wayland component. I will also check internally but please check with the Wayland community for any other debug suggestions.

    Regards,
    Krunal

  • Hi, Krunal-san.

    I agree with you. I will check the Wayland community.

    If you know anything about it, please let me know.

    Regards,

    Takayuki

  • Hi, Krunal-san.

    This issue is improved by updating ti-sgx-ddk-um from 06_01_00_08 to 06_03_00_106.

    I think the difference between each version is the replacement of the library libpvr* with libGLES*_PVR_MESA.

    Please let me know the affection of this update, because the behavior of my application using weston-egl is changed due to this update and there isn't the description of this difference in SDK's release note.

    Regards,

    Takayuki

  • Hello Takayuki,

    Please refer to the following link: http://software-dl.ti.com/processor-sdk-linux/esd/docs/latest/linux/Foundational_Components/Graphics/Migration_From_Prior_Releases.html#from-processor-sdk-6-1-to-6-2-for-am3-4-5-6. I am assuming you are still observing memory leaks but less compared to PSDK6.1.

    Regards,
    Krunal

  • Hi Krunal-san,

    Thank you for your information. I observed that the amount of memory leaks was very low.

    Regarding backward compatibility, it says there are exceptions, but is there a problem when using GLES textures?

    The sample code for textures that worked in PSDK 6.1 does not work correctly after changing to PSDK 6.3.

    I have attached this sample code.

    /*
     * Copyright © 2011 Benjamin Franzke
     *
     * Permission is hereby granted, free of charge, to any person obtaining a
     * copy of this software and associated documentation files (the "Software"),
     * to deal in the Software without restriction, including without limitation
     * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     * and/or sell copies of the Software, and to permit persons to whom the
     * Software is furnished to do so, subject to the following conditions:
     *
     * The above copyright notice and this permission notice (including the next
     * paragraph) shall be included in all copies or substantial portions of the
     * Software.
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     * DEALINGS IN THE SOFTWARE.
     */
    
    #include "config.h"
    
    #include <stdint.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <stdbool.h>
    #include <math.h>
    #include <assert.h>
    #include <signal.h>
    
    #include <linux/input.h>
    
    #include <wayland-client.h>
    #include <wayland-egl.h>
    
    #include <GLES2/gl2.h>
    #include <GLES2/gl2ext.h>
    #include <EGL/egl.h>
    #include <EGL/eglext.h>
    
    #include "xdg-shell-unstable-v6-client-protocol.h"
    #include <sys/types.h>
    #include <unistd.h>
    
    #include "shared/helpers.h"
    #include "shared/platform.h"
    #include "weston-egl-ext.h"
    
    struct window;
    struct seat;
    
    struct display {
    	struct wl_display *display;
    	struct wl_registry *registry;
    	struct wl_compositor *compositor;
    	struct zxdg_shell_v6 *shell;
    	struct wl_seat *seat;
    	struct wl_touch *touch;
    	struct wl_shm *shm;
    	struct {
    		EGLDisplay dpy;
    		EGLContext ctx;
    		EGLConfig conf;
    	} egl;
    	struct window *window;
    
    	PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC swap_buffers_with_damage;
    };
    
    struct geometry {
    	int width, height;
    };
    
    struct window {
    	struct display *display;
    	struct geometry geometry, window_size;
    	struct {
    		GLuint pos;
    		GLuint col;
    		GLint attr_uv;
    		GLint unif_texture;
    		GLuint texture_id;
    	} gl;
    	uint32_t benchmark_time, frames;
    	struct wl_egl_window *native;
    	struct wl_surface *surface;
    	struct zxdg_surface_v6 *xdg_surface;
    	struct zxdg_toplevel_v6 *xdg_toplevel;
    	EGLSurface egl_surface;
    	struct wl_callback *callback;
    	int fullscreen, maximized, opaque, buffer_size, frame_sync, delay;
    	bool wait_for_configure;
    };
    
    static const char *vert_shader_text =
    	"attribute vec4 pos;\n"
    	"attribute vec2 attr_uv;\n"
    	"varying vec2 vary_uv;\n"
    	"void main() {\n"
    	"  gl_Position = pos;\n"
    	"  vary_uv = attr_uv;\n"
    	"}\n";
    
    static const char *frag_shader_text =
    	"precision mediump float;\n"
    	"varying vec2 vary_uv;\n"
    	"uniform sampler2D unif_texture;\n"
    	"void main() {\n"
    	"  gl_FragColor = texture2D(unif_texture, vary_uv);\n"
    	"}\n";
    
    static int running = 1;
    static uint32_t time_global = 0;
    struct window *window;
    struct display *display;
    
    static void
    init_egl(struct display *display, struct window *window)
    {
    	static const struct {
    		char *extension, *entrypoint;
    	} swap_damage_ext_to_entrypoint[] = {
    		{
    			.extension = "EGL_EXT_swap_buffers_with_damage",
    			.entrypoint = "eglSwapBuffersWithDamageEXT",
    		},
    		{
    			.extension = "EGL_KHR_swap_buffers_with_damage",
    			.entrypoint = "eglSwapBuffersWithDamageKHR",
    		},
    	};
    
    	static const EGLint context_attribs[] = {
    		EGL_CONTEXT_CLIENT_VERSION, 2,
    		EGL_NONE
    	};
    	const char *extensions;
    
    	EGLint config_attribs[] = {
    		EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
    		EGL_RED_SIZE, 1,
    		EGL_GREEN_SIZE, 1,
    		EGL_BLUE_SIZE, 1,
    		EGL_ALPHA_SIZE, 1,
    		EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
    		EGL_NONE
    	};
    
    	EGLint major, minor, n, count, i, size;
    	EGLConfig *configs;
    	EGLBoolean ret;
    
    	if (window->opaque || window->buffer_size == 16)
    		config_attribs[9] = 0;
    
    	display->egl.dpy =
    		weston_platform_get_egl_display(EGL_PLATFORM_WAYLAND_KHR,
    						display->display, NULL);
    	assert(display->egl.dpy);
    
    	ret = eglInitialize(display->egl.dpy, &major, &minor);
    	assert(ret == EGL_TRUE);
    	ret = eglBindAPI(EGL_OPENGL_ES_API);
    	assert(ret == EGL_TRUE);
    
    	if (!eglGetConfigs(display->egl.dpy, NULL, 0, &count) || count < 1)
    		assert(0);
    
    	configs = calloc(count, sizeof *configs);
    	assert(configs);
    
    	ret = eglChooseConfig(display->egl.dpy, config_attribs,
    			      configs, count, &n);
    	assert(ret && n >= 1);
    
    	for (i = 0; i < n; i++) {
    		eglGetConfigAttrib(display->egl.dpy,
    				   configs[i], EGL_BUFFER_SIZE, &size);
    		if (window->buffer_size == size) {
    			display->egl.conf = configs[i];
    			break;
    		}
    	}
    	free(configs);
    	if (display->egl.conf == NULL) {
    		fprintf(stderr, "did not find config with buffer size %d\n",
    			window->buffer_size);
    		exit(EXIT_FAILURE);
    	}
    
    	display->egl.ctx = eglCreateContext(display->egl.dpy,
    					    display->egl.conf,
    					    EGL_NO_CONTEXT, context_attribs);
    	assert(display->egl.ctx);
    
    	display->swap_buffers_with_damage = NULL;
    	extensions = eglQueryString(display->egl.dpy, EGL_EXTENSIONS);
    	if (extensions &&
    	    weston_check_egl_extension(extensions, "EGL_EXT_buffer_age")) {
    		for (i = 0; i < (int) ARRAY_LENGTH(swap_damage_ext_to_entrypoint); i++) {
    			if (weston_check_egl_extension(extensions,
    						       swap_damage_ext_to_entrypoint[i].extension)) {
    				/* The EXTPROC is identical to the KHR one */
    				display->swap_buffers_with_damage =
    					(PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC)
    					eglGetProcAddress(swap_damage_ext_to_entrypoint[i].entrypoint);
    				break;
    			}
    		}
    	}
    
    	if (display->swap_buffers_with_damage)
    		printf("has EGL_EXT_buffer_age and %s\n", swap_damage_ext_to_entrypoint[i].extension);
    
    }
    
    static void
    fini_egl(struct display *display)
    {
    	eglTerminate(display->egl.dpy);
    	eglReleaseThread();
    }
    
    static GLuint
    create_shader(struct window *window, const char *source, GLenum shader_type)
    {
    	GLuint shader;
    	GLint status;
    
    	shader = glCreateShader(shader_type);
    	assert(shader != 0);
    
    	glShaderSource(shader, 1, (const char **) &source, NULL);
    	assert(glGetError() == GL_NO_ERROR);
    	glCompileShader(shader);
    	assert(glGetError() == GL_NO_ERROR);
    
    	glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
    	assert(glGetError() == GL_NO_ERROR);
    	if (!status) {
    		char log[1000];
    		GLsizei len;
    		glGetShaderInfoLog(shader, 1000, &len, log);
    		fprintf(stderr, "Error: compiling %s: %*s\n",
    			shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment",
    			len, log);
    		exit(1);
    	}
    
    	return shader;
    }
    static void
    create_texture(struct window *window)
    {
    	glGenTextures(1, &window->gl.texture_id);
    	assert(window->gl.texture_id != 0);
    	assert(glGetError() == GL_NO_ERROR);
    
    	glBindTexture(GL_TEXTURE_2D, window->gl.texture_id);
    	assert(glGetError() == GL_NO_ERROR);
    
    	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 800 , 480, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
    	assert(glGetError() == GL_NO_ERROR);
    
    	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    
    	assert(glGetError() == GL_NO_ERROR);
    }
    
    static void
    init_gl(struct window *window)
    {
    	GLuint frag, vert;
    	GLuint program;
    	GLint status;
    
    	frag = create_shader(window, frag_shader_text, GL_FRAGMENT_SHADER);
    	vert = create_shader(window, vert_shader_text, GL_VERTEX_SHADER);
    
    	program = glCreateProgram();
    	glAttachShader(program, frag);
    	glAttachShader(program, vert);
    	glLinkProgram(program);
    	assert(glGetError() == GL_NO_ERROR);
    
    	glGetProgramiv(program, GL_LINK_STATUS, &status);
    	if (!status) {
    		char log[1000];
    		GLsizei len;
    		glGetProgramInfoLog(program, 1000, &len, log);
    		fprintf(stderr, "Error: linking:\n%*s\n", len, log);
    		exit(1);
    	}
    
    	glUseProgram(program);
    
    	create_texture(window);
    
    	window->gl.pos = 0;
    	window->gl.col = 1;
    	window->gl.attr_uv = 2;
    
    	glBindAttribLocation(program, window->gl.pos, "pos");
    	glBindAttribLocation(program, window->gl.attr_uv, "attr_uv");
    	window->gl.unif_texture = glGetUniformLocation(program, "unif_texture");
    	assert(window->gl.unif_texture >= 0);
    	glLinkProgram(program);
    	assert(glGetError() == GL_NO_ERROR);
    }
    
    static void
    handle_surface_configure(void *data, struct zxdg_surface_v6 *surface,
    			 uint32_t serial)
    {
    	struct window *window = data;
    
    	zxdg_surface_v6_ack_configure(surface, serial);
    
    	window->wait_for_configure = false;
    }
    
    static const struct zxdg_surface_v6_listener xdg_surface_listener = {
    	handle_surface_configure
    };
    
    static void
    handle_toplevel_configure(void *data, struct zxdg_toplevel_v6 *toplevel,
    			  int32_t width, int32_t height,
    			  struct wl_array *states)
    {
    	struct window *window = data;
    	uint32_t *p;
    
    	window->fullscreen = 0;
    	window->maximized = 0;
    	wl_array_for_each(p, states) {
    		uint32_t state = *p;
    		switch (state) {
    		case ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN:
    			window->fullscreen = 1;
    			break;
    		case ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED:
    			window->maximized = 1;
    			break;
    		}
    	}
    
    	if (width > 0 && height > 0) {
    		if (!window->fullscreen && !window->maximized) {
    			window->window_size.width = width;
    			window->window_size.height = height;
    		}
    		window->geometry.width = width;
    		window->geometry.height = height;
    	} else if (!window->fullscreen && !window->maximized) {
    		window->geometry = window->window_size;
    	}
    
    	if (window->native)
    		wl_egl_window_resize(window->native,
    				     window->geometry.width,
    				     window->geometry.height, 0, 0);
    }
    
    static void
    handle_toplevel_close(void *data, struct zxdg_toplevel_v6 *xdg_toplevel)
    {
    }
    
    static const struct zxdg_toplevel_v6_listener xdg_toplevel_listener = {
    	handle_toplevel_configure,
    	handle_toplevel_close,
    };
    
    static void
    create_xdg_surface(struct window *window, struct display *display)
    {
    	window->xdg_surface = zxdg_shell_v6_get_xdg_surface(display->shell,
    							    window->surface);
    	zxdg_surface_v6_add_listener(window->xdg_surface,
    				     &xdg_surface_listener, window);
    
    	window->xdg_toplevel =
    		zxdg_surface_v6_get_toplevel(window->xdg_surface);
    	zxdg_toplevel_v6_add_listener(window->xdg_toplevel,
    				      &xdg_toplevel_listener, window);
    
    	zxdg_toplevel_v6_set_title(window->xdg_toplevel, "simple-egl");
    
    	window->wait_for_configure = true;
    	wl_surface_commit(window->surface);
    }
    
    static void
    create_surface(struct window *window)
    {
    	struct display *display = window->display;
    	EGLBoolean ret;
    
    	window->surface = wl_compositor_create_surface(display->compositor);
    
    	window->native =
    		wl_egl_window_create(window->surface,
    				     window->geometry.width,
    				     window->geometry.height);
    	window->egl_surface =
    		weston_platform_create_egl_surface(display->egl.dpy,
    						   display->egl.conf,
    						   window->native, NULL);
    
    
    	if (display->shell) {
    		create_xdg_surface(window, display);
    	} else {
    		assert(0);
    	}
    
    	ret = eglMakeCurrent(window->display->egl.dpy, window->egl_surface,
    			     window->egl_surface, window->display->egl.ctx);
    	assert(ret == EGL_TRUE);
    
    	if (!window->frame_sync)
    		eglSwapInterval(display->egl.dpy, 0);
    
    	if (!display->shell)
    		return;
    
    	if (window->fullscreen)
    		zxdg_toplevel_v6_set_fullscreen(window->xdg_toplevel, NULL);
    }
    
    static void
    destroy_surface(struct window *window)
    {
    	/* Required, otherwise segfault in egl_dri2.c: dri2_make_current()
    	 * on eglReleaseThread(). */
    	eglMakeCurrent(window->display->egl.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE,
    		       EGL_NO_CONTEXT);
    
    	weston_platform_destroy_egl_surface(window->display->egl.dpy,
    					    window->egl_surface);
    	wl_egl_window_destroy(window->native);
    
    	if (window->xdg_toplevel)
    		zxdg_toplevel_v6_destroy(window->xdg_toplevel);
    	if (window->xdg_surface)
    		zxdg_surface_v6_destroy(window->xdg_surface);
    	wl_surface_destroy(window->surface);
    
    	if (window->callback)
    		wl_callback_destroy(window->callback);
    }
    
    static void
    paint_pixels(void *image, int padding, int width, int height, uint32_t time)
    {
            const int halfh = padding + (height - padding * 2) / 2;
            const int halfw = padding + (width  - padding * 2) / 2;
            int ir, or;
            uint32_t *pixel = image;
            int y;
    
            /* squared radii thresholds */
            or = (halfw < halfh ? halfw : halfh) - 8;
            ir = or - 32;
            or *= or;
            ir *= ir;
    
            pixel += padding * width;
            for (y = padding; y < height - padding; y++) {
                    int x;
                    int y2 = (y - halfh) * (y - halfh);
    
                    pixel += padding;
                    for (x = padding; x < width - padding; x++) {
                            uint32_t v;
    
                            /* squared distance from center */
                            int r2 = (x - halfw) * (x - halfw) + y2;
    
                            if (r2 < ir)
                                    v = (r2 / 32 + time / 64) * 0x0080401;
                            else if (r2 < or)
                                    v = (y + time / 32) * 0x0080401;
                            else
                                    v = (x + time / 16) * 0x0080401;
                            v &= 0x00ffffff;
    
                            /* cross if compositor uses X from XRGB as alpha */
                            //if (abs(x - y) > 6 && abs(x + y - height) > 6)
                            //       v |= 0xff000000;
    
                            *pixel++ = v;
    
                    }
    
                    pixel += padding;
            }
    }
    
    static void
    redraw(void *data, struct wl_callback *callback, uint32_t time)
    {
    	struct window *window = data;
    	struct display *display = window->display;
    	static const GLfloat verts[4][2] = {
    		{-1.0, -1.0},
    		{-1.0,  1.0},
    		{ 1.0, -1.0},
    		{ 1.0,  1.0}
    	};
    	
    	static const GLfloat uv[4][2] = {
    		{0, 0},
    		{0, 1},
    		{1, 0},
    		{1, 1}
    	};
    
    	GLuint pixels[800 * 480] = {};
    	//paint pixels Mandelbrot
    	paint_pixels(pixels, 0, window->geometry.width, window->geometry.height, time_global);
    	time_global = time_global + 100;
    
    	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    	assert(glGetError() == GL_NO_ERROR);
    
    	static const uint32_t benchmark_interval = 5;
    	struct wl_region *region;
    	EGLint rect[4];
    	EGLint buffer_age = 0;
    	struct timeval tv;
    
    	assert(window->callback == callback);
    	window->callback = NULL;
    
    	if (callback)
    		wl_callback_destroy(callback);
    
    	gettimeofday(&tv, NULL);
    	time = tv.tv_sec * 1000 + tv.tv_usec / 1000;
    	if (window->frames == 0)
    		window->benchmark_time = time;
    	if (time - window->benchmark_time > (benchmark_interval * 1000)) {
    		printf("%d frames in %d seconds: %f fps\n",
    		       window->frames,
    		       benchmark_interval,
    		       (float) window->frames / benchmark_interval);
    		window->benchmark_time = time;
    		window->frames = 0;
    	}
    	
    	//Update texture
    	glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 800, 480, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
    	assert(glGetError() == GL_NO_ERROR);
    
    	if (display->swap_buffers_with_damage)
    		eglQuerySurface(display->egl.dpy, window->egl_surface,
    				EGL_BUFFER_AGE_EXT, &buffer_age);
    
    	glViewport(0, 0, window->geometry.width, window->geometry.height);
    	assert(glGetError() == GL_NO_ERROR);
    
    	glClearColor(1.0, 0.0, 0.0, 0.5);
    	glClear(GL_COLOR_BUFFER_BIT);
    	assert(glGetError() == GL_NO_ERROR);
    
    	glVertexAttribPointer(window->gl.pos, 2, GL_FLOAT, GL_FALSE, 0, verts);
    	glVertexAttribPointer(window->gl.attr_uv, 2, GL_FLOAT, GL_FALSE, 0, uv);
    	glEnableVertexAttribArray(window->gl.pos);
    	glEnableVertexAttribArray(window->gl.attr_uv);
    
    	glUniform1i(window->gl.unif_texture, 0);
    	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    
    	assert(glGetError() == GL_NO_ERROR);
    
    	usleep(window->delay);
    
    	if (window->opaque || window->fullscreen) {
    		region = wl_compositor_create_region(window->display->compositor);
    		wl_region_add(region, 0, 0,
    			      window->geometry.width,
    			      window->geometry.height);
    		wl_surface_set_opaque_region(window->surface, region);
    		wl_region_destroy(region);
    	} else {
    		wl_surface_set_opaque_region(window->surface, NULL);
    	}
    
    	if (display->swap_buffers_with_damage && buffer_age > 0) {
    		rect[0] = window->geometry.width / 4 - 1;
    		rect[1] = window->geometry.height / 4 - 1;
    		rect[2] = window->geometry.width / 2 + 2;
    		rect[3] = window->geometry.height / 2 + 2;
    		display->swap_buffers_with_damage(display->egl.dpy,
    						  window->egl_surface,
    						  rect, 1);
    	} else {
    		eglSwapBuffers(display->egl.dpy, window->egl_surface);
    	}
    	window->frames++;
    }
    
    static void
    touch_handle_down(void *data, struct wl_touch *wl_touch,
    		  uint32_t serial, uint32_t time, struct wl_surface *surface,
    		  int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
    {
    }
    
    static void
    touch_handle_up(void *data, struct wl_touch *wl_touch,
    		uint32_t serial, uint32_t time, int32_t id)
    {
    }
    
    static void
    touch_handle_motion(void *data, struct wl_touch *wl_touch,
    		    uint32_t time, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
    {
    }
    
    static void
    touch_handle_frame(void *data, struct wl_touch *wl_touch)
    {
    }
    
    static void
    touch_handle_cancel(void *data, struct wl_touch *wl_touch)
    {
    }
    
    static const struct wl_touch_listener touch_listener = {
    	touch_handle_down,
    	touch_handle_up,
    	touch_handle_motion,
    	touch_handle_frame,
    	touch_handle_cancel,
    };
    
    
    static void
    seat_handle_capabilities(void *data, struct wl_seat *seat,
    			 enum wl_seat_capability caps)
    {
    	struct display *d = data;
    
    	if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !d->touch) {
    		d->touch = wl_seat_get_touch(seat);
    		wl_touch_set_user_data(d->touch, d);
    		wl_touch_add_listener(d->touch, &touch_listener, d);
    	} else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && d->touch) {
    		wl_touch_destroy(d->touch);
    		d->touch = NULL;
    	}
    }
    
    static const struct wl_seat_listener seat_listener = {
    	seat_handle_capabilities,
    };
    
    static void
    xdg_shell_ping(void *data, struct zxdg_shell_v6 *shell, uint32_t serial)
    {
    	zxdg_shell_v6_pong(shell, serial);
    }
    
    static const struct zxdg_shell_v6_listener xdg_shell_listener = {
    	xdg_shell_ping,
    };
    
    static void
    registry_handle_global(void *data, struct wl_registry *registry,
    		       uint32_t name, const char *interface, uint32_t version)
    {
    	struct display *d = data;
    
    	if (strcmp(interface, "wl_compositor") == 0) {
    		d->compositor =
    			wl_registry_bind(registry, name,
    					 &wl_compositor_interface,
    					 MIN(version, 4));
    	} else if (strcmp(interface, "zxdg_shell_v6") == 0) {
    		d->shell = wl_registry_bind(registry, name,
    					    &zxdg_shell_v6_interface, 1);
    		zxdg_shell_v6_add_listener(d->shell, &xdg_shell_listener, d);
    	} else if (strcmp(interface, "wl_seat") == 0) {
    		d->seat = wl_registry_bind(registry, name,
    					   &wl_seat_interface, 1);
    		wl_seat_add_listener(d->seat, &seat_listener, d);
    	} else if (strcmp(interface, "wl_shm") == 0) {
    		d->shm = wl_registry_bind(registry, name,
    					  &wl_shm_interface, 1);
    		}
    }
    
    
    static void
    registry_handle_global_remove(void *data, struct wl_registry *registry,
    			      uint32_t name)
    {
    }
    
    static const struct wl_registry_listener registry_listener = {
    	registry_handle_global,
    	registry_handle_global_remove
    };
    
    
    static void 
    display_init()
    {
            display = malloc(sizeof *display);
            if (display == NULL) {
                    exit(1);
            }
    
            window = malloc(sizeof *window);
            if (window == NULL) {
                    exit(1);
            }
    
    	window->display = display;
    	display->window = window;
    	window->geometry.width  = 800;
    	window->geometry.height = 480;
    	window->window_size = window->geometry;
    	window->buffer_size = 32;
    	window->frame_sync = 1;
    	window->delay = 0;
    
    	display->display = wl_display_connect(NULL);
    	assert(display->display);
    
    	display->registry = wl_display_get_registry(display->display);
    	wl_registry_add_listener(display->registry,
    				 &registry_listener, display);
    
    	wl_display_roundtrip(display->display);
    
    	init_egl(display, window);
    	create_surface(window);
    	init_gl(window);
    }
    
    static void
    signal_int(int signum)
    {
    	running = 0;
    }
    
    int  
    main(int argc, char **argv)
    {
    	struct sigaction sigint;
    	int ret = 0;
    	display_init();
    	assert(glGetError() == GL_NO_ERROR);
    
    	sigint.sa_handler = signal_int;
    	sigemptyset(&sigint.sa_mask);
    	sigint.sa_flags = SA_RESETHAND;
    	sigaction(SIGINT, &sigint, NULL);
    
    	while(running && ret != -1){
    		if (window->wait_for_configure){
    			wl_display_dispatch(display->display);
    		} else {
    			wl_display_dispatch_pending(display->display);
    			redraw(window, NULL, 0);
    		}
    		assert(glGetError() == GL_NO_ERROR);
    	}
            fprintf(stderr, "simple-egl exiting\n");
            destroy_surface(window);
            fini_egl(display);
    
            if (display->shell)
                    zxdg_shell_v6_destroy(display->shell);
    
            if (display->compositor)
                    wl_compositor_destroy(display->compositor);
    
            wl_registry_destroy(display->registry);
            wl_display_flush(display->display);
            wl_display_disconnect(display->display);
    
            return 0;
    }
    

    The problem is that it only refreshes the center part of the screen after the screen refreshes for the first few seconds.

    It just looks like half of the specified screen size.

    The part I would like you to check is whether the flow from glGenTextures in the create_texture function to eglSwapBuffers in the redraw function is correct.

    Regards,

    Takayuki

  • Hello Takayuki,

    There should not be any impact on the OpenGLES API calls. I am wondering if you could share images of your output behavior.

    Regards,

    Krunal

  • Hi Krunal-san,

    The output images are attached.

    The first one, sample-PSDK6_1.mp4, works fine; the second one, sample-PSDK6_3.mp4, only redraws the center of the screen.

    Regards,

    Takayuki

  • Hello Takayuki,

    Could you please share how to compile the code or the binary so I could run on my setup as well?

    Regards,
    Krunal

  • Hi Krunal-san,

    I have attached the binary.

    You can copy weston-simple-egl to any directory of am335x-evm (or BeagleBone Black) on the ti-linux provided by PSDK 6_1 or 6_3 and run ./weston-simple-egl. You can see the pattern is displayed.

    And I'll show you how to compile.

    On the PSDK 6_1 or 6_3, you can copy the source I send 2 days ago to <tisdk_root>/build/arago-tmp-external-arm-toolchain/work/armv7at2hf-neon-linux-gnueabi/weston/5.0.0-r0.arago34.tisdk0/weston-5.0.0/clients/,

    and run <tisdk_root>/build/arago-tmp-external-arm-toolchain/work/armv7at2hf-neon-linux-gnueabi/weston/5.0.0-r0.arago34.tisdk0/temp/run.do_compile, the binary is built in build/ directory.

    weston-simple-egl.zip

    Regards,

    Takayuki

  • Hello Takayuki,

    Thank you for the sharing the above information. I will try running the application on my setup and I will get back to you in 24-48 hours.

    Regards,
    Krunal

  • Hello Takayuki,

    I was able to replicate the issue on my setup and I am internally checking if a certain API is not supported.

    Regards,
    Krunal

  • Hi Krunal-san,

    Thank you for your investigating. 

    If a certain API is not supported, I don't know why "/usr/bin/SGX/demos/Wayland/" applications which may be used Texture API work well. Can I get the source of "/usr/bin/SGX/demos/Wayland/" ? 

    Regards, 

    Takayuki

  • Hello Takayuki,

    Based on my internal discussion, there should not be any impact on the API. The source code could be found in the following repo: https://github.com/powervr-graphics/Native_SDK. Also, your application is very similar to "weston-simple-shm" and I do not see the same behavior with that app. I am wondering if you have tried running "weston-simple-shm" app?

    Regards,
    Krunal

  • Hi Krunal-san,

    I'll try to https://github.com/powervr-graphics/Native_SDK, thank you for your information.

    As you said, my application refers to "weston-simple-shm" and I have confirmed that "shm" application works fine.

    One possibility is that there may be a problem with the EGL API. As I understand it, EGL is responsible for allocating memory such as context. I think the problem may be caused by the failure to allocate the memory area for the texture.

    Regards,

    Takayuki

  • Hi Krunal-san,

    What version of the source is the binary for the "img-pvr-sdk" package based on?  I tried to build the source for the R20.2-v5.6 tag, but I got the following message and could not run "OpenGLESIntroducingPVRUtils" which contains TexImage2D():

    "Exit message set to: InitView threw a runtime exception with message: 'OpenGL ES Error occured: [GL_INVALID_VALUE] -- [textureUpload]: glTexImage2D'
    InitView() failed with pvr error 'Error while initializing'."

    Regards, 

    Takayuki

  • Hello Takayuki,

    I am reviewing your log internally and I will get back to you shortly.

    Regards,
    Krunal

  • Are you observing the errors for all the tests or just OpenGLESIntroducingPVRUtils?

    Regards,

    Krunal

  • Hi Krunal-san,

    Thanks for your reviewing. I am observing the error for just OpenGLESIntroducingPVRUtils.

    It's about the problem with only the center of the screen being updated,  I found it was caused by lines 598-605 of the source code. We had overlooked the fact that PSDK6.3 supports eglSwapBuffersWithDamageEXT.

    	if (display->swap_buffers_with_damage && buffer_age > 0) {
    		rect[0] = window->geometry.width / 4 - 1;
    		rect[1] = window->geometry.height / 4 - 1;
    		rect[2] = window->geometry.width / 2 + 2;
    		rect[3] = window->geometry.height / 2 + 2;
    		display->swap_buffers_with_damage(display->egl.dpy,
    						  window->egl_surface,
    						  rect, 1);

    So, I made the following changes to get the full screen drawing update.

    		rect[0] = 0;
    		rect[1] = 0;
    		rect[2] = window->geometry.width;
    		rect[3] = window->geometry.height;

    However, there is a tearing-like phenomenon in the upper right corner of the screen. This is also probably a problem with my source code. 

    Let me sort out the issue for once. The problem in the first place was that ti-sgx-ddk-um on PSDK6.1 was causing memory leaks. To be honest, from a developer's point of view, it is not desirable to have such a big change as PSDK 6.3. Is it possible for you to create a patch for ti-sgx-ddk-um of PSDK 6.1 to improve memory leaks?

    Regards,

    Takayuki

  • Hello Takayuki,

    Thank you for the feedback and I will raise an internal ticket to investigate for any bugs on PSDK6.1.

    Regards,
    Krunal

  • Hello Takayuki,

    I am wondering if your application is running as expected on PSDK6.03. Also, what release are you planning on using for your development?

    Regards,
    Krunal

  • Hi Krunal-san,
    I really appreciate your investigation. I'm not able to work it as expected on PSDK6.03 yet.

    Our development is going well, excluding GPU, and we're planning to release on PSDK6.01. So we would be very happy if this problem could be improved on this version.

    Regards,

    Takayuki

  • Hello Takayuki,

    Please correct me if I am wrong but your application uses the Wayland compositor and you are observing memory leaks. The leaks are observed less on PSDK6.3 as opposed to PSDK6.1. Based on your testing, you believe the leaks could be coming from the GPU drivers.

    Regards,
    Krunal

  • Hi Krunal-san,

    That is correct with your understanding.

    Regards,

    Takayuki

  • Hello Takayuki,

    Could you please share the memory leak difference between PSDK6.1 and PSDK6.3? I am not observing a major delta on my test setup.

    Regards,
    Krunal

  • Hi Krunal-san,

    My step is to run "weston-simple-egl" on each PSDK. 

    I have attached the log of my observation of memory leakage. 

    14:57:00						
    root@am335x-evm:~#	free					
    	total	used	free	shared	buff/cache	available
    Mem:	1025504	60576	739688	20520	225240	922120
    Swap:	0	0	0			
    15:23:00						
    root@am335x-evm:~#	free					
    	total	used	free	shared	buff/cache	available
    Mem:	1025504	60936	739120	20692	225448	921588
    Swap:	0	0	0			
    15:37:00						
    root@am335x-evm:~#	free				
    	total	used	free	shared	buff/cache	available
    Mem:	1025504	60896	739060	20784	225548	921536
    Swap:	0	0	0			
    15:51:00						
    root@am335x-evm:~#	free					
    	total	used	free	shared	buff/cache	available
    Mem:	1025504	61052	738800	20880	225652	921284
    Swap:	0	0	0			
    						
    16:00:00				
    root@am335x-evm:~#	free				
    	total	used	free	shared	buff/cache	available
    Mem:	1025504	61116	738664	20940	225724	921160
    Swap:	0	0	0

    17:47	2021/3/17						
    free							
    	total	used	free	shared	buffers	cached	
    Mem:	248544	179128	69416	2372	3076	132392	204884
    -/+	buffers/cache:	43660	204884				
    Swap:	0	0	0				
    							
    8:31	2021/3/18						
    free							
    	total	used	free	shared	buffers	cached	
    Mem:	248544	179060	69484	2372	3076	132392	204952
    -/+	buffers/cache:	43592	204952				
    Swap:	0	0	0

    I'm sorry for the difference of format but the important point is that the value of "available" column in the PSDK 6.01 file was decreasing 10MB for 2hours and the value in 4th column of each "-/+" row was slightly increasing or almost the same for an half day. 

    Also, I have attached the result of the valgrind. These results show that the definitely leak on PSDK6.3 is lesser than PSDK6.1 .

    weston-simple-egl-valgrind-20210317-am335x-evm-PSDK6_03.logweston-simple-egl-valgrind-20210315-am335x-evm-PSDK6_01.log

    Regards, 

    Takayuki.

  • Hello Takayuki,

    I apologize for the delayed response but I tested weston-simple-egl on various platforms with different GPU. I am observing similar behavior on all the platforms. I am wondering if the Wayland/Weston community has given any feedback because it does not seem like a GPU issue.

    Regards,
    Krunal

  • Hi Krunal-san,

    Thanks for your investigation. I would like to know about your investigation. 

    1. Did you observe the memory leakage on all the platforms?

    2. What is the reason why that memory leakage is caused by Wayland/Weston?

    And I haven't get any feedback from the Wayland/Weston community yet and there isn't any issue which is similar to the problem. 

    Regards,

    Takayuki

  • Hello Takayuki,

    I have attached our log from the TDA4 platform and it uses a different GPU than AM335x. Also, if we run the application without Weston, the memory leaks are not observed. If there was an issue with the GPU driver, the leaks would be observed on drm based application as well. It all depends on how the Wayland/Weston community manage their buffer allocations. As seen by the valgrind logs, I am wondering if certain buffers are not getting freed. 

    Regards,
    Krunal

    j7-weston-simple-egl-valgrind.log