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.

Linux/AM5728: EGLImage memory leak

Part Number: AM5728

Tool/software: Linux

I'm using EGLImage for read RGBA texture to the GPU, The version of PSDK I am using is 04.00.00.04 and I've also tried ddk-um [cf8cd62] (um: gles2: Fix PVR_DBG level in 1RGB FBO completeness check)

When my application executes below code, it runs successfully for ~1 minutes befeore I begin to get repeating console message :

In case of using CMEM:
eglCreateImageKHR(...) returns error 0x300C
PVR:(Error): [ 1165-> 1178] < CreateBuffer():866|ERROR> cannot mmap buffer : Cannot allocate memo
ry [0, ]
PVR:(Error): [ 1165-> 1178] < CreateDrawable():938|ERROR> Error mapping 0 buffer [0, ]

In case of using OMAP:
omapdrm omapdrm.0: could not remap: -12 (3)
PVR_K:(Error): DmaBufImportAndAcquirePhysAddr: dma_buf_map_attachment failed: -885075008
eglCreateImageKHR(...) returns error 0x300C

Here is my code (using cmem): 

for (;;)                                                                                        
{                                                                                               
// --> Alloc CMEM                                                                               
     CMEM_AllocParams   cmemParams = {0,};                                                             
     cmemParams->type     = CMEM_HEAP;                                                          
     cmemParams->flags    = CMEM_CACHED;                                                        
     cmemParams->alignment = 0;                                                                 
     void* cmem_buf = CMEM_alloc2( 2, Width * Height * 4, (CMEM_AllocParams*)&cmemParams );      
// --> GBM Import                                                                               
     struct gbm_import_fd_data GbmImportData;                                                   
     GbmImportData.fd = CMEM_export_dmabuf( cmem_buf );                                         
     GbmImportData.width     = Width;                                                           
     GbmImportData.height = Height;                                                             
     GbmImportData.stride = Width * 4;                                                          
     GbmImportData.format = GBM_BO_FORMAT_ARGB8888;                                             
     struct gbm_bo* lpGbmBo = gbm_bo_import( GbmDev, GBM_BO_IMPORT_FD, &GbmImportData,          
                                             GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT );       
// --> Create EGLImage, Texture                                                                 
     EGLImageKHR EglImage = eglCreateImageKHR( EGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR,
                                               static_cast<EGLClientBuffer>(lpGbmBo), NULL );   
     GLuint Tb;                                                                                 
     glGenTextures( 1, &Tb );                                                                   
     glBindTexture( GL_TEXTURE_EXTERNAL_OES, Tb );                                              
     glEGLImageTargetTexture2DOES( GL_TEXTURE_EXTERNAL_OES, EglImage );                         
                                                                                                
// <-- Destroy EGLImage, Texture                                                                
     glDeleteTextures( 1, &Tb );                                                                
     eglDestroyImageKHR( EGLDisplay, EglImage );                                                
                                                                                                
// <-- Destroy GBM Object                                                                       
     gbm_bo_destroy( lpGbmBo );                                                                 
// <-- Destroy CMEM buf                                                                         
     close( GbmImportData.fd );                                                                 
     CMEM_free( cmem_buf, (CMEM_AllocParams*)&cmemParams );                                     
}                                                                                               
                                                                                                

1. Without eglCreateImageKHR(), gbm-omap alloc/dealloc has no problem

2. I tested with EGL_LINUX_DMA_BUF(YUYV), but there is no memory leak

  • The software team have been notified. They will respond here.
  • Can you share the standalone test application that we can run at our end and replicate the issue?
  • Thank you for the response.

    Here I attached source file as you requested.

    It is from kmscube(git://git.ti.com/glsdk/kmscube.git) and you can easily build with it (just add -lticmem flag)

    kmscube.c
    /*
     * Copyright (c) 2012 Arvin Schnell <arvin.schnell@gmail.com>
     * Copyright (c) 2012 Rob Clark <rob@ti.com>
     * Copyright (c) 2013 Anand Balagopalakrishnan <anandb@ti.com>
     *
     * 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, sub license,
     * 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 NON-INFRINGEMENT. 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.
     */
    
    /* Based on a egl cube test app originally written by Arvin Schnell */
    
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <string.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdbool.h>
    #include <unistd.h>
    #include <errno.h>
    #include <signal.h>
    
    #include <xf86drm.h>
    #include <xf86drmMode.h>
    #include <drm_fourcc.h>
    #include <gbm.h>
    #include <linux/dma-buf.h>
    #include <ti/cmem.h>
    
    #include <GLES2/gl2.h>
    #include <GLES2/gl2ext.h>
    #include <EGL/egl.h>
    #include <EGL/eglext.h>
    
    #include "esUtil.h"
    
    #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
    
    #define MAX_DISPLAYS 	(4)
    uint8_t DISP_ID = 0;
    uint8_t all_display = 0;
    int8_t connector_id = -1;
    
    #define GL_ERR_CHECK							\
        do {										\
            GLenum e = glGetError();				\
            if ( e != GL_NO_ERROR )					\
            {										\
    			printf("GL error 0x%04X\n", e);	\
            }										\
        } while ( 0 )
    #define GL_CHECK(x)								\
    	x;											\
    	GL_ERR_CHECK;
    
    #define EGL_ERR_CHECK							\
        do {										\
            EGLenum e = eglGetError();				\
            if ( (e != 0) && (e != EGL_SUCCESS) )	\
            {										\
    			printf("EGL error 0x%04X\n", e);	\
            }										\
        } while ( 0 )
    #define EGL_CHECK(x)							\
    	x;											\
    	EGL_ERR_CHECK;
    
    typedef EGLImageKHR (eglCreateImageKHR_t)( EGLDisplay Dpy, EGLContext Ctx,
    										   EGLenum Target, EGLClientBuffer Buffer,
    										   const EGLint *AttribList );
    typedef EGLBoolean (eglDestroyImageKHR_t)( EGLDisplay Dpy, EGLImageKHR Image );
    typedef void (glEGLImageTargetTexture2DOES_t)( GLenum Target, GLeglImageOES Image );
    typedef EGLSyncKHR (eglCreateSyncKHR_t)( EGLDisplay Dpy, EGLenum Type,
    										 const EGLint *AttribList );
    typedef EGLBoolean (eglDestroySyncKHR_t)( EGLDisplay Dpy, EGLSyncKHR Sync );
    typedef EGLint (eglClientWaitSyncKHR_t)( EGLDisplay Dpy, EGLSyncKHR Sync,
    										 EGLint Flags, EGLTimeKHR Timeout );
    
    
    static struct {
    	EGLDisplay display;
    	EGLConfig config;
    	EGLContext context;
    	EGLSurface surface;
    	GLuint program;
    	GLint modelviewmatrix, modelviewprojectionmatrix, normalmatrix;
    	GLuint vbo;
    	GLuint positionsoffset, colorsoffset, normalsoffset;
    	GLuint vertex_shader, fragment_shader;
    	eglCreateImageKHR_t* eglCreateImageKHR;
    	eglDestroyImageKHR_t* eglDestroyImageKHR;
    	glEGLImageTargetTexture2DOES_t* glEGLImageTargetTexture2DOES;
    } gl;
    
    static struct {
    	struct gbm_device *dev;
    	struct gbm_surface *surface;
    } gbm;
    
    static struct {
    	int fd;
    	uint32_t ndisp;
    	uint32_t crtc_id[MAX_DISPLAYS];
    	uint32_t connector_id[MAX_DISPLAYS];
    	uint32_t resource_id;
    	uint32_t encoder[MAX_DISPLAYS];
    	uint32_t format[MAX_DISPLAYS];
    	drmModeModeInfo *mode[MAX_DISPLAYS];
    	drmModeConnector *connectors[MAX_DISPLAYS];
    } drm;
    
    struct drm_fb {
    	struct gbm_bo *bo;
    	uint32_t fb_id;
    };
    
    static uint32_t drm_fmt_to_gbm_fmt(uint32_t fmt)
    {
    	switch (fmt) {
    		case DRM_FORMAT_XRGB8888:
    			printf("xrgb8888\n");
    			return GBM_FORMAT_XRGB8888;
    		case DRM_FORMAT_ARGB8888:
    			printf("argb8888\n");
    			return GBM_FORMAT_ARGB8888;
    		case DRM_FORMAT_RGB565:
    			return GBM_FORMAT_RGB565;
    		default:
    			printf("Unsupported DRM format: 0x%x", fmt);
    			return GBM_FORMAT_XRGB8888;
    	}
    }
    
    static bool search_plane_format(uint32_t desired_format, int formats_count, uint32_t* formats)
    {
    	int i;
    
    	for ( i = 0; i < formats_count; i++)
    	{
    		if (desired_format == formats[i])
    			return true;
    	}
    
    	return false;
    }
    
    int get_drm_prop_val(int fd, drmModeObjectPropertiesPtr props,
    	                 const char *name, unsigned int *p_val) {
    	drmModePropertyPtr p;
    	unsigned int i, prop_id = 0; /* Property ID should always be > 0 */
    
    	for (i = 0; !prop_id && i < props->count_props; i++) {
    		p = drmModeGetProperty(fd, props->props[i]);
    		if (!strcmp(p->name, name)){
    			prop_id = p->prop_id;
    			break;
    		}
    		drmModeFreeProperty(p);
    	}
    
    	if (!prop_id) {
    		printf("Could not find %s property\n", name);
    		return(-1);
    	}
    
    	drmModeFreeProperty(p);
    	*p_val = props->prop_values[i];
    	return 0;
    }
    
    static bool set_drm_format(void)
    {
    	/* desired DRM format in order */
    	static const uint32_t drm_formats[] = {DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888, DRM_FORMAT_RGB565};
    	drmModePlaneRes *plane_res;
    	bool found = false;
    	int i,k;
    
    	drmSetClientCap(drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
    
    	plane_res  = drmModeGetPlaneResources(drm.fd);
    
    	if (!plane_res) {
    		printf("drmModeGetPlaneResources failed: %s\n", strerror(errno));
    		drmSetClientCap(drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 0);
    		return false;
    	}
    
    	/*
    	 * find the plane connected to crtc_id (the primary plane) and then find the desired pixel format
    	 * from the plane format list
    	 */
    	for (i = 0; i < plane_res->count_planes; i++)
    	{
    		drmModePlane *plane = drmModeGetPlane(drm.fd, plane_res->planes[i]);
    		drmModeObjectProperties *props;
    		unsigned int plane_type;
    
    		if(plane == NULL)
    			continue;
    
    		props = drmModeObjectGetProperties(drm.fd, plane->plane_id, DRM_MODE_OBJECT_PLANE);
    
    		if(props == NULL){
    			printf("plane (%d) properties not found\n",  plane->plane_id);
    			drmModeFreePlane(plane);
    			continue;
    		}
    
    		if(get_drm_prop_val(drm.fd, props, "type",  &plane_type) < 0)
    		{
    			printf("plane (%d) type value not found\n",  plane->plane_id);
    			drmModeFreeObjectProperties(props);
    			drmModeFreePlane(plane);
    			continue;
    		}
    
    		if (plane_type != DRM_PLANE_TYPE_PRIMARY)
    		{
    			drmModeFreeObjectProperties(props);
    			drmModeFreePlane(plane);
    			continue;
    		}
    		else if (!plane->crtc_id)
    		{
    			plane->crtc_id = drm.crtc_id[drm.ndisp];
    		}
    
    		drmModeFreeObjectProperties(props);
    
    		if (plane->crtc_id == drm.crtc_id[drm.ndisp])
    		{
    			for (k = 0; k < ARRAY_SIZE(drm_formats); k++)
    			{
    				if (search_plane_format(drm_formats[k], plane->count_formats, plane->formats))
    				{
    					drm.format[drm.ndisp] = drm_formats[k];
    					drmModeFreePlane(plane);
    					drmModeFreePlaneResources(plane_res);
    					drmSetClientCap(drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 0);
    					return true;
    				}
    			}
    		}
    
    		drmModeFreePlane(plane);
    	}
    
    	drmModeFreePlaneResources(plane_res);
    	drmSetClientCap(drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 0);
    	return false;
    }
    
    static int init_drm(void)
    {
    	static const char *modules[] = {
    			"omapdrm", "tilcdc", "i915", "radeon", "nouveau", "vmwgfx", "exynos"
    	};
    	drmModeRes *resources;
    	drmModeConnector *connector = NULL;
    	drmModeEncoder *encoder = NULL;
    	drmModeCrtc *crtc = NULL;
    
    	int i, j, k;
    	uint32_t maxRes, curRes;
    
    	for (i = 0; i < ARRAY_SIZE(modules); i++) {
    		printf("trying to load module %s...", modules[i]);
    		drm.fd = drmOpen(modules[i], NULL);
    		if (drm.fd < 0) {
    			printf("failed.\n");
    		} else {
    			printf("success.\n");
    			break;
    		}
    	}
    
    	if (drm.fd < 0) {
    		printf("could not open drm device\n");
    		return -1;
    	}
    
    	resources = drmModeGetResources(drm.fd);
    	if (!resources) {
    		printf("drmModeGetResources failed: %s\n", strerror(errno));
    		return -1;
    	}
    	drm.resource_id = (uint32_t) resources;
    
    	/* find a connected connector: */
    	for (i = 0; i < resources->count_connectors; i++) {
    		connector = drmModeGetConnector(drm.fd, resources->connectors[i]);
    		if (connector->connection == DRM_MODE_CONNECTED) {
    
    			/* find the matched encoders */
    			for (j=0; j<connector->count_encoders; j++) {
    				encoder = drmModeGetEncoder(drm.fd, connector->encoders[j]);
    
    				/* Take the fisrt one, if none is assigned */
    				if (!connector->encoder_id)
    				{
    					connector->encoder_id = encoder->encoder_id;
    				}
    
    				if (encoder->encoder_id == connector->encoder_id)
    				{
    					/* find the first valid CRTC if not assigned */
    					if (!encoder->crtc_id)
    					{
    						for (k = 0; k < resources->count_crtcs; ++k) {
    							/* check whether this CRTC works with the encoder */
    							if (!(encoder->possible_crtcs & (1 << k)))
    								continue;
    
    							encoder->crtc_id = resources->crtcs[k];
    							break;
    						}
    
    						if (!encoder->crtc_id)
    						{
    							printf("Encoder(%d): no CRTC find!\n", encoder->encoder_id);
    							drmModeFreeEncoder(encoder);
    							encoder = NULL;
    							continue;
    						}
    					}
    
    					break;
    				}
    
    				drmModeFreeEncoder(encoder);
    				encoder = NULL;
    			}
    
    			if (!encoder) {
    				printf("Connector (%d): no encoder!\n", connector->connector_id);
    				drmModeFreeConnector(connector);
    				continue;
    			}
    
    			/* choose the current or first supported mode */
    			crtc = drmModeGetCrtc(drm.fd, encoder->crtc_id);
    			for (j = 0; j < connector->count_modes; j++)
    			{
    				if (crtc->mode_valid)
    				{
    					if ((connector->modes[j].hdisplay == crtc->width) &&
    					(connector->modes[j].vdisplay == crtc->height))
    					{
    						drm.mode[drm.ndisp] = &connector->modes[j];
    						break;
    					}
    				}
    				else
    				{
    					if ((connector->modes[j].hdisplay == crtc->x) &&
    					   (connector->modes[j].vdisplay == crtc->y))
    					{
    						drm.mode[drm.ndisp] = &connector->modes[j];
    						break;
    					}
    				}
    			}
    
    			if(j >= connector->count_modes)
    				drm.mode[drm.ndisp] = &connector->modes[0];
    
    			drm.connector_id[drm.ndisp] = connector->connector_id;
    
    			drm.encoder[drm.ndisp]  = (uint32_t) encoder;
    			drm.crtc_id[drm.ndisp] = encoder->crtc_id;
    			drm.connectors[drm.ndisp] = connector;
    
    			if (!set_drm_format())
    			{
    				// Error handling
    				printf("No desired pixel format found!\n");
    				return -1;
    			}
    
    			printf("### Display [%d]: CRTC = %d, Connector = %d, format = 0x%x\n", drm.ndisp, drm.crtc_id[drm.ndisp], drm.connector_id[drm.ndisp], drm.format[drm.ndisp]);
    			printf("\tMode chosen [%s] : Clock => %d, Vertical refresh => %d, Type => %d\n", drm.mode[drm.ndisp]->name, drm.mode[drm.ndisp]->clock, drm.mode[drm.ndisp]->vrefresh, drm.mode[drm.ndisp]->type);
    			printf("\tHorizontal => %d, %d, %d, %d, %d\n", drm.mode[drm.ndisp]->hdisplay, drm.mode[drm.ndisp]->hsync_start, drm.mode[drm.ndisp]->hsync_end, drm.mode[drm.ndisp]->htotal, drm.mode[drm.ndisp]->hskew);
    			printf("\tVertical => %d, %d, %d, %d, %d\n", drm.mode[drm.ndisp]->vdisplay, drm.mode[drm.ndisp]->vsync_start, drm.mode[drm.ndisp]->vsync_end, drm.mode[drm.ndisp]->vtotal, drm.mode[drm.ndisp]->vscan);
    
    			/* If a connector_id is specified, use the corresponding display */
    			if ((connector_id != -1) && (connector_id == drm.connector_id[drm.ndisp]))
    				DISP_ID = drm.ndisp;
    
    			/* If all displays are enabled, choose the connector with maximum
    			* resolution as the primary display */
    			if (all_display) {
    				maxRes = drm.mode[DISP_ID]->vdisplay * drm.mode[DISP_ID]->hdisplay;
    				curRes = drm.mode[drm.ndisp]->vdisplay * drm.mode[drm.ndisp]->hdisplay;
    
    				if (curRes > maxRes)
    					DISP_ID = drm.ndisp;
    			}
    
    			drm.ndisp++;
    		} else {
    			drmModeFreeConnector(connector);
    		}
    	}
    
    	if (drm.ndisp == 0) {
    		/* we could be fancy and listen for hotplug events and wait for
    		 * a connector..
    		 */
    		printf("no connected connector!\n");
    		return -1;
    	}
    
    	return 0;
    }
    
    static int init_gbm(void)
    {
    	gbm.dev = gbm_create_device(drm.fd);
    
    	gbm.surface = gbm_surface_create(gbm.dev,
    			drm.mode[DISP_ID]->hdisplay, drm.mode[DISP_ID]->vdisplay,
    			drm_fmt_to_gbm_fmt(drm.format[DISP_ID]),
    			GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
    	if (!gbm.surface) {
    		printf("failed to create gbm surface\n");
    		return -1;
    	}
    
    	return 0;
    }
    
    static int init_gl(void)
    {
    	EGLint major, minor, n;
    	GLint ret;
    
    	static const GLfloat vVertices[] = {
    			// front
    			-0.5f, -0.5f, +0.5f, // point blue
    			+0.5f, -0.5f, +0.5f, // point magenta
    			-0.5f, +0.5f, +0.5f, // point cyan
    			+0.5f, +0.5f, +0.5f, // point white
    			// back
    			+0.5f, -0.5f, -0.5f, // point red
    			-0.5f, -0.5f, -0.5f, // point black
    			+0.5f, +0.5f, -0.5f, // point yellow
    			-0.5f, +0.5f, -0.5f, // point green
    			// right
    			+0.5f, -0.5f, +0.5f, // point magenta
    			+0.5f, -0.5f, -0.5f, // point red
    			+0.5f, +0.5f, +0.5f, // point white
    			+0.5f, +0.5f, -0.5f, // point yellow
    			// left
    			-0.5f, -0.5f, -0.5f, // point black
    			-0.5f, -0.5f, +0.5f, // point blue
    			-0.5f, +0.5f, -0.5f, // point green
    			-0.5f, +0.5f, +0.5f, // point cyan
    			// top
    			-0.5f, +0.5f, +0.5f, // point cyan
    			+0.5f, +0.5f, +0.5f, // point white
    			-0.5f, +0.5f, -0.5f, // point green
    			+0.5f, +0.5f, -0.5f, // point yellow
    			// bottom
    			-0.5f, -0.5f, -0.5f, // point black
    			+0.5f, -0.5f, -0.5f, // point red
    			-0.5f, -0.5f, +0.5f, // point blue
    			+0.5f, -0.5f, +0.5f  // point magenta
    	};
    
    	static const GLfloat vColors[] = {
    			// front
    			0.0f,  0.0f,  1.0f, // blue
    			1.0f,  0.0f,  1.0f, // magenta
    			0.0f,  1.0f,  1.0f, // cyan
    			1.0f,  1.0f,  1.0f, // white
    			// back
    			1.0f,  0.0f,  0.0f, // red
    			0.0f,  0.0f,  0.0f, // black
    			1.0f,  1.0f,  0.0f, // yellow
    			0.0f,  1.0f,  0.0f, // green
    			// right
    			1.0f,  0.0f,  1.0f, // magenta
    			1.0f,  0.0f,  0.0f, // red
    			1.0f,  1.0f,  1.0f, // white
    			1.0f,  1.0f,  0.0f, // yellow
    			// left
    			0.0f,  0.0f,  0.0f, // black
    			0.0f,  0.0f,  1.0f, // blue
    			0.0f,  1.0f,  0.0f, // green
    			0.0f,  1.0f,  1.0f, // cyan
    			// top
    			0.0f,  1.0f,  1.0f, // cyan
    			1.0f,  1.0f,  1.0f, // white
    			0.0f,  1.0f,  0.0f, // green
    			1.0f,  1.0f,  0.0f, // yellow
    			// bottom
    			0.0f,  0.0f,  0.0f, // black
    			1.0f,  0.0f,  0.0f, // red
    			0.0f,  0.0f,  1.0f, // blue
    			1.0f,  0.0f,  1.0f  // magenta
    	};
    
    	static const GLfloat vNormals[] = {
    			// front
    			+0.0f, +0.0f, +1.0f, // forward
    			+0.0f, +0.0f, +1.0f, // forward
    			+0.0f, +0.0f, +1.0f, // forward
    			+0.0f, +0.0f, +1.0f, // forward
    			// back
    			+0.0f, +0.0f, -1.0f, // backbard
    			+0.0f, +0.0f, -1.0f, // backbard
    			+0.0f, +0.0f, -1.0f, // backbard
    			+0.0f, +0.0f, -1.0f, // backbard
    			// right
    			+1.0f, +0.0f, +0.0f, // right
    			+1.0f, +0.0f, +0.0f, // right
    			+1.0f, +0.0f, +0.0f, // right
    			+1.0f, +0.0f, +0.0f, // right
    			// left
    			-1.0f, +0.0f, +0.0f, // left
    			-1.0f, +0.0f, +0.0f, // left
    			-1.0f, +0.0f, +0.0f, // left
    			-1.0f, +0.0f, +0.0f, // left
    			// top
    			+0.0f, +1.0f, +0.0f, // up
    			+0.0f, +1.0f, +0.0f, // up
    			+0.0f, +1.0f, +0.0f, // up
    			+0.0f, +1.0f, +0.0f, // up
    			// bottom
    			+0.0f, -1.0f, +0.0f, // down
    			+0.0f, -1.0f, +0.0f, // down
    			+0.0f, -1.0f, +0.0f, // down
    			+0.0f, -1.0f, +0.0f  // down
    	};
    
    	static const EGLint context_attribs[] = {
    		EGL_CONTEXT_CLIENT_VERSION, 2,
    		EGL_NONE
    	};
    
    	static const EGLint config_attribs[] = {
    		EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
    		EGL_RED_SIZE, 1,
    		EGL_GREEN_SIZE, 1,
    		EGL_BLUE_SIZE, 1,
    		EGL_ALPHA_SIZE, 0,
    		EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
    		EGL_NONE
    	};
    
    	static const char *vertex_shader_source =
    			"uniform mat4 modelviewMatrix;      \n"
    			"uniform mat4 modelviewprojectionMatrix;\n"
    			"uniform mat3 normalMatrix;         \n"
    			"                                   \n"
    			"attribute vec4 in_position;        \n"
    			"attribute vec3 in_normal;          \n"
    			"attribute vec4 in_color;           \n"
    			"\n"
    			"vec4 lightSource = vec4(2.0, 2.0, 20.0, 0.0);\n"
    			"                                   \n"
    			"varying vec4 vVaryingColor;        \n"
    			"                                   \n"
    			"void main()                        \n"
    			"{                                  \n"
    			"    gl_Position = modelviewprojectionMatrix * in_position;\n"
    			"    vec3 vEyeNormal = normalMatrix * in_normal;\n"
    			"    vec4 vPosition4 = modelviewMatrix * in_position;\n"
    			"    vec3 vPosition3 = vPosition4.xyz / vPosition4.w;\n"
    			"    vec3 vLightDir = normalize(lightSource.xyz - vPosition3);\n"
    			"    float diff = max(0.0, dot(vEyeNormal, vLightDir));\n"
    			"    vVaryingColor = vec4(diff * in_color.rgb, 1.0);\n"
    			"}                                  \n";
    
    	static const char *fragment_shader_source =
    			"precision mediump float;           \n"
    			"                                   \n"
    			"varying vec4 vVaryingColor;        \n"
    			"                                   \n"
    			"void main()                        \n"
    			"{                                  \n"
    			"    gl_FragColor = vVaryingColor;  \n"
    			"}                                  \n";
    
    	gl.display = eglGetDisplay(gbm.dev);
    
    	if (!eglInitialize(gl.display, &major, &minor)) {
    		printf("failed to initialize\n");
    		return -1;
    	}
    
    	printf("Using display %p with EGL version %d.%d\n",
    			gl.display, major, minor);
    
    	printf("EGL Version \"%s\"\n", eglQueryString(gl.display, EGL_VERSION));
    	printf("EGL Vendor \"%s\"\n", eglQueryString(gl.display, EGL_VENDOR));
    	printf("EGL Extensions \"%s\"\n", eglQueryString(gl.display, EGL_EXTENSIONS));
    
    	if (!eglBindAPI(EGL_OPENGL_ES_API)) {
    		printf("failed to bind api EGL_OPENGL_ES_API\n");
    		return -1;
    	}
    
    	if (!eglChooseConfig(gl.display, config_attribs, &gl.config, 1, &n) || n != 1) {
    		printf("failed to choose config: %d\n", n);
    		return -1;
    	}
    
    	gl.context = eglCreateContext(gl.display, gl.config,
    			EGL_NO_CONTEXT, context_attribs);
    	if (gl.context == NULL) {
    		printf("failed to create context\n");
    		return -1;
    	}
    
    	gl.surface = eglCreateWindowSurface(gl.display, gl.config, gbm.surface, NULL);
    	if (gl.surface == EGL_NO_SURFACE) {
    		printf("failed to create egl surface\n");
    		return -1;
    	}
    
    	/* connect the context to the surface */
    	eglMakeCurrent(gl.display, gl.surface, gl.surface, gl.context);
    
    
    	if ((gl.eglCreateImageKHR =
    		 (eglCreateImageKHR_t*)eglGetProcAddress("eglCreateImageKHR")) == NULL)
    	{
    		printf("Failed to eglGetProcAddress(\"eglCreateImageKHR\")\n");
    	}
    	if ((gl.eglDestroyImageKHR =
    		 (eglCreateImageKHR_t*)eglGetProcAddress("eglDestroyImageKHR")) == NULL)
    	{
    		printf("Failed to eglGetProcAddress(\"eglDestroyImageKHR\")\n");
    	}
    	if ((gl.glEGLImageTargetTexture2DOES =
    		 (eglCreateImageKHR_t*)eglGetProcAddress("glEGLImageTargetTexture2DOES")) == NULL)
    	{
    		printf("Failed to eglGetProcAddress(\"glEGLImageTargetTexture2DOES\")\n");
    	}
    
    	gl.vertex_shader = glCreateShader(GL_VERTEX_SHADER);
    
    	glShaderSource(gl.vertex_shader, 1, &vertex_shader_source, NULL);
    	glCompileShader(gl.vertex_shader);
    
    	glGetShaderiv(gl.vertex_shader, GL_COMPILE_STATUS, &ret);
    	if (!ret) {
    		char *log;
    
    		printf("vertex shader compilation failed!:\n");
    		glGetShaderiv(gl.vertex_shader, GL_INFO_LOG_LENGTH, &ret);
    		if (ret > 1) {
    			log = malloc(ret);
    			glGetShaderInfoLog(gl.vertex_shader, ret, NULL, log);
    			printf("%s", log);
    		}
    
    		return -1;
    	}
    
    	gl.fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
    
    	glShaderSource(gl.fragment_shader, 1, &fragment_shader_source, NULL);
    	glCompileShader(gl.fragment_shader);
    
    	glGetShaderiv(gl.fragment_shader, GL_COMPILE_STATUS, &ret);
    	if (!ret) {
    		char *log;
    
    		printf("fragment shader compilation failed!:\n");
    		glGetShaderiv(gl.fragment_shader, GL_INFO_LOG_LENGTH, &ret);
    
    		if (ret > 1) {
    			log = malloc(ret);
    			glGetShaderInfoLog(gl.fragment_shader, ret, NULL, log);
    			printf("%s", log);
    		}
    
    		return -1;
    	}
    
    	gl.program = glCreateProgram();
    
    	glAttachShader(gl.program, gl.vertex_shader);
    	glAttachShader(gl.program, gl.fragment_shader);
    
    	glBindAttribLocation(gl.program, 0, "in_position");
    	glBindAttribLocation(gl.program, 1, "in_normal");
    	glBindAttribLocation(gl.program, 2, "in_color");
    
    	glLinkProgram(gl.program);
    
    	glGetProgramiv(gl.program, GL_LINK_STATUS, &ret);
    	if (!ret) {
    		char *log;
    
    		printf("program linking failed!:\n");
    		glGetProgramiv(gl.program, GL_INFO_LOG_LENGTH, &ret);
    
    		if (ret > 1) {
    			log = malloc(ret);
    			glGetProgramInfoLog(gl.program, ret, NULL, log);
    			printf("%s", log);
    		}
    
    		return -1;
    	}
    
    	glUseProgram(gl.program);
    
    	gl.modelviewmatrix = glGetUniformLocation(gl.program, "modelviewMatrix");
    	gl.modelviewprojectionmatrix = glGetUniformLocation(gl.program, "modelviewprojectionMatrix");
    	gl.normalmatrix = glGetUniformLocation(gl.program, "normalMatrix");
    
    	glViewport(0, 0, drm.mode[DISP_ID]->hdisplay, drm.mode[DISP_ID]->vdisplay);
    	glEnable(GL_CULL_FACE);
    
    	gl.positionsoffset = 0;
    	gl.colorsoffset = sizeof(vVertices);
    	gl.normalsoffset = sizeof(vVertices) + sizeof(vColors);
    	glGenBuffers(1, &gl.vbo);
    	glBindBuffer(GL_ARRAY_BUFFER, gl.vbo);
    	glBufferData(GL_ARRAY_BUFFER, sizeof(vVertices) + sizeof(vColors) + sizeof(vNormals), 0, GL_STATIC_DRAW);
    	glBufferSubData(GL_ARRAY_BUFFER, gl.positionsoffset, sizeof(vVertices), &vVertices[0]);
    	glBufferSubData(GL_ARRAY_BUFFER, gl.colorsoffset, sizeof(vColors), &vColors[0]);
    	glBufferSubData(GL_ARRAY_BUFFER, gl.normalsoffset, sizeof(vNormals), &vNormals[0]);
    	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)gl.positionsoffset);
    	glEnableVertexAttribArray(0);
    	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)gl.normalsoffset);
    	glEnableVertexAttribArray(1);
    	glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)gl.colorsoffset);
    	glEnableVertexAttribArray(2);
    
    	return 0;
    }
    
    static void exit_gbm(void)
    {
            gbm_surface_destroy(gbm.surface);
            gbm_device_destroy(gbm.dev);
            return;
    }
    
    static void exit_gl(void)
    {
            glDeleteProgram(gl.program);
            glDeleteBuffers(1, &gl.vbo);
            glDeleteShader(gl.fragment_shader);
            glDeleteShader(gl.vertex_shader);
            eglDestroySurface(gl.display, gl.surface);
            eglDestroyContext(gl.display, gl.context);
            eglTerminate(gl.display);
            return;
    }
    
    static void exit_drm(void)
    {
    
            drmModeRes *resources;
            int i;
    
            resources = (drmModeRes *)drm.resource_id;
            for (i = 0; i < resources->count_connectors; i++) {
                    drmModeFreeEncoder(drm.encoder[i]);
                    drmModeFreeConnector(drm.connectors[i]);
            }
            drmModeFreeResources(drm.resource_id);
            drmClose(drm.fd);
            return;
    }
    
    void cleanup_kmscube(void)
    {
    	exit_gl();
    	exit_gbm();
    	exit_drm();
    	printf("Cleanup of GL, GBM and DRM completed\n");
    	return;
    }
    
    static void draw(uint32_t i)
    {
    	ESMatrix modelview;
    
    	/* clear the color buffer */
    	glClearColor(0.5, 0.5, 0.5, 1.0);
    	glClear(GL_COLOR_BUFFER_BIT);
    
    	esMatrixLoadIdentity(&modelview);
    	esTranslate(&modelview, 0.0f, 0.0f, -8.0f);
    	esRotate(&modelview, 45.0f + (0.25f * i), 1.0f, 0.0f, 0.0f);
    	esRotate(&modelview, 45.0f - (0.5f * i), 0.0f, 1.0f, 0.0f);
    	esRotate(&modelview, 10.0f + (0.15f * i), 0.0f, 0.0f, 1.0f);
    
    	GLfloat aspect = (GLfloat)(drm.mode[DISP_ID]->vdisplay) / (GLfloat)(drm.mode[DISP_ID]->hdisplay);
    
    	ESMatrix projection;
    	esMatrixLoadIdentity(&projection);
    	esFrustum(&projection, -2.8f, +2.8f, -2.8f * aspect, +2.8f * aspect, 6.0f, 10.0f);
    
    	ESMatrix modelviewprojection;
    	esMatrixLoadIdentity(&modelviewprojection);
    	esMatrixMultiply(&modelviewprojection, &modelview, &projection);
    
    	float normal[9];
    	normal[0] = modelview.m[0][0];
    	normal[1] = modelview.m[0][1];
    	normal[2] = modelview.m[0][2];
    	normal[3] = modelview.m[1][0];
    	normal[4] = modelview.m[1][1];
    	normal[5] = modelview.m[1][2];
    	normal[6] = modelview.m[2][0];
    	normal[7] = modelview.m[2][1];
    	normal[8] = modelview.m[2][2];
    
    	glUniformMatrix4fv(gl.modelviewmatrix, 1, GL_FALSE, &modelview.m[0][0]);
    	glUniformMatrix4fv(gl.modelviewprojectionmatrix, 1, GL_FALSE, &modelviewprojection.m[0][0]);
    	glUniformMatrix3fv(gl.normalmatrix, 1, GL_FALSE, normal);
    
    	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    	glDrawArrays(GL_TRIANGLE_STRIP, 4, 4);
    	glDrawArrays(GL_TRIANGLE_STRIP, 8, 4);
    	glDrawArrays(GL_TRIANGLE_STRIP, 12, 4);
    	glDrawArrays(GL_TRIANGLE_STRIP, 16, 4);
    	glDrawArrays(GL_TRIANGLE_STRIP, 20, 4);
    }
    
    static void
    drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
    {
    	struct drm_fb *fb = data;
    	struct gbm_device *gbm = gbm_bo_get_device(bo);
    
    	if (fb->fb_id)
    		drmModeRmFB(drm.fd, fb->fb_id);
    
    	free(fb);
    }
    
    static struct drm_fb * drm_fb_get_from_bo(struct gbm_bo *bo)
    {
    	struct drm_fb *fb = gbm_bo_get_user_data(bo);
    	uint32_t width, height, format;
    	uint32_t bo_handles[4] = {0}, offsets[4] = {0}, pitches[4] = {0};
    	int ret;
    
    	if (fb)
    		return fb;
    
    	fb = calloc(1, sizeof *fb);
    	fb->bo = bo;
    
    	width = gbm_bo_get_width(bo);
    	height = gbm_bo_get_height(bo);
    	pitches[0] = gbm_bo_get_stride(bo);
    	bo_handles[0] = gbm_bo_get_handle(bo).u32;
    	format = gbm_bo_get_format(bo);
    
    	ret = drmModeAddFB2(drm.fd, width, height, format, bo_handles, pitches, offsets, &fb->fb_id, 0);
    	if (ret) {
    		printf("failed to create fb: %s\n", strerror(errno));
    		free(fb);
    		return NULL;
    	}
    
    	gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
    
    	return fb;
    }
    
    static void page_flip_handler(int fd, unsigned int frame,
    		  unsigned int sec, unsigned int usec, void *data)
    {
    	int *waiting_for_flip = data;
    	*waiting_for_flip = 0;
    }
    
    void print_usage()
    {
    	printf("Usage : kmscube <options>\n");
    	printf("\t-h : Help\n");
    	printf("\t-a : Enable all displays\n");
    	printf("\t-c <id> : Display using connector_id [if not specified, use the first connected connector]\n");
    	printf("\t-n <number> (optional): Number of frames to render\n");
    }
    
    int kms_signalhandler(int signum)
    {
    	switch(signum) {
    	case SIGINT:
            case SIGTERM:
                    /* Allow the pending page flip requests to be completed before
                     * the teardown sequence */
                    sleep(1);
                    printf("Handling signal number = %d\n", signum);
    		cleanup_kmscube();
    		break;
    	default:
    		printf("Unknown signal\n");
    		break;
    	}
    	exit(1);
    }
    
    int main(int argc, char *argv[])
    {
    	fd_set fds;
    	drmEventContext evctx = {
    			.version = DRM_EVENT_CONTEXT_VERSION,
    			.page_flip_handler = page_flip_handler,
    	};
    	struct gbm_bo *bo;
    	struct drm_fb *fb;
    	uint32_t i = 0;
    	int ret;
    	int opt;
    	int frame_count = -1;
    
    	signal(SIGINT, kms_signalhandler);
    	signal(SIGTERM, kms_signalhandler);
    
    	while ((opt = getopt(argc, argv, "ahc:n:")) != -1) {
    		switch(opt) {
    		case 'a':
    			all_display = 1;
    			break;
    
    		case 'h':
    			print_usage();
    			return 0;
    
    		case 'c':
    			connector_id = atoi(optarg);
    			break;
    		case 'n':
    			frame_count = atoi(optarg);
    			break;
    
    
    		default:
    			printf("Undefined option %s\n", argv[optind]);
    			print_usage();
    			return -1;
    		}
    	}
    
    	if (all_display) {
    		printf("### Enabling all displays\n");
    		connector_id = -1;
    	}
    
    	ret = init_drm();
    	if (ret) {
    		printf("failed to initialize DRM\n");
    		return ret;
    	}
    	printf("### Primary display => ConnectorId = %d, Resolution = %dx%d\n",
    			drm.connector_id[DISP_ID], drm.mode[DISP_ID]->hdisplay,
    			drm.mode[DISP_ID]->vdisplay);
    
    	FD_ZERO(&fds);
    	FD_SET(drm.fd, &fds);
    
    	ret = init_gbm();
    	if (ret) {
    		printf("failed to initialize GBM\n");
    		return ret;
    	}
    
    	ret = init_gl();
    	if (ret) {
    		printf("failed to initialize EGL\n");
    		return ret;
    	}
    
    	/* clear the color buffer */
    	glClearColor(0.5, 0.5, 0.5, 1.0);
    	glClear(GL_COLOR_BUFFER_BIT);
    	eglSwapBuffers(gl.display, gl.surface);
    	bo = gbm_surface_lock_front_buffer(gbm.surface);
    	fb = drm_fb_get_from_bo(bo);
    
    	/* set mode: */
    	if (all_display) {
    		for (i=0; i<drm.ndisp; i++) {
    			ret = drmModeSetCrtc(drm.fd, drm.crtc_id[i], fb->fb_id, 0, 0,
    					&drm.connector_id[i], 1, drm.mode[i]);
    			if (ret) {
    				printf("display %d failed to set mode: %s\n", i, strerror(errno));
    				return ret;
    			}
    		}
    	} else {
    		ret = drmModeSetCrtc(drm.fd, drm.crtc_id[DISP_ID], fb->fb_id,
    				0, 0, &drm.connector_id[DISP_ID], 1, drm.mode[DISP_ID]);
    		if (ret) {
    			printf("display %d failed to set mode: %s\n", DISP_ID, strerror(errno));
    			return ret;
    		}
    	}
    
    	#define USE_EGLIMAGE
    
    	int Width = drm.mode[DISP_ID]->vdisplay;
    	int Height = drm.mode[DISP_ID]->hdisplay;
    	CMEM_init();
    
    	while (frame_count != 0) {
    		// --> Alloc CMEM
    		CMEM_AllocParams	cmemParams = {0, };
    		cmemParams.type		 = CMEM_HEAP;
    		cmemParams.flags	 = CMEM_CACHED;
    		cmemParams.alignment = 0;
    
    		void*	cmem_buf	 = CMEM_alloc2(2, Width*Height*4, &cmemParams);
    
    		// --> GBM Import
    		struct gbm_import_fd_data	GbmImportData = {0,};
    		GbmImportData.fd		= CMEM_export_dmabuf(cmem_buf);
    		GbmImportData.width		= Width;
    		GbmImportData.height	= Height;
    		GbmImportData.stride	= Width * 4;
    		GbmImportData.format	= GBM_BO_FORMAT_ARGB8888;
    
    		struct gbm_bo*	lpGbmBo	= gbm_bo_import(gbm.dev, GBM_BO_IMPORT_FD, &GbmImportData,
    												GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT );
    
    		// --> Create EGLImage, Texture
    #if defined (USE_EGLIMAGE)
    		EGLImageKHR EglImage =
    			EGL_CHECK(gl.eglCreateImageKHR( gl.display, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR,
    											(EGLClientBuffer)lpGbmBo, NULL ));
    #endif
    		GLuint	Tb;
    		GL_CHECK(glGenTextures(1, &Tb));
    		GL_CHECK(glBindTexture(GL_TEXTURE_EXTERNAL_OES, Tb));
    #if defined (USE_EGLIMAGE)
    		GL_CHECK(gl.glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, EglImage));
    #endif
    		// <-- Destroy EGLImage, Texture
    		GL_CHECK(glDeleteTextures(1, &Tb));
    #if defined (USE_EGLIMAGE)
    		EGL_CHECK(gl.eglDestroyImageKHR(gl.display, EglImage));
    #endif
    		// <-- Destroy GBM Object
    		gbm_bo_destroy(lpGbmBo);
    		close(GbmImportData.fd);
    		CMEM_free(cmem_buf, &cmemParams);
    
    		printf("frames[%d]\n", frame_count--);
    	}
    
    	cleanup_kmscube();
    	printf("\n Exiting kmscube \n");
    
    	return ret;
    }
    

  • I am not able to run the standalone application. I get following error -

    argb8888
    Using display 0x1 with EGL version 1.4
    EGL Version "1.4 build 1.14@3699939 (MAIN)"
    EGL Vendor "Imagination Technologies"
    EGL Extensions "EGL_IMG_client_api_ogl EGL_KHR_image EGL_KHR_image_base EGL_KHR_gl_texture_2D_image EGL_KHR_gl_texture_cubemap_image EGL_KHR_gl_renderbuffer_image EGL_KHR_vg_parent_ima[1051436.173792] CMEMK Error: ioctl: no heap available in block 2
    ge EGL_IMG_cl_image EGL_KHR_fence_sync EGL_IMG_context_priority [1051436.182530] CMEMK Error: get_phys: Unable to find phys addr for 0x0
    EGL_IMG_hibernate_process EGL_IMG_image_plane_attribs EGL_KHR_su[1051436.194575] CMEMK Error: get_phys: get_user_pages() failed: -14
    rfaceless_context EGL_KHR_wait_sync EGL_KHR_create_context EGL_W[1051436.206380] CMEMK Error: GETPHYS: Failed to convert virtual (null) to physical.
    L_bind_wayland_display EGL_EXT_image_dma_buf_import"
    CMEM Error: allocHeap: ioctl CMEM_IOCALLOCHEAPCACHED failed: -1
    CMEM Error: export_dmabuf: Failed to export to dmabuf 0
    PVR:(Error): [ 5204-> 5204] < gbm_pvr_bo_create_common():262|ERROR> Failed to allocate DBM buffer: Operation not permitted [0, ]
    PVR:(Error): [ 5204-> 5204] < WSEGL_CreatePixmapDrawable():1006|ERROR> condition [ hNativePixmap != NULL] failed [0, ]
    EGL error 0x300C
    GL error 0x0502
    EGL error 0x300C
    Segmentation fault (core dumped)
  • Maybe you will need to modify the dtsi file to allocate the cmem buffer.
    I reattach the source file using a omap_drm buffer instead of cmem.

    - kmscube.c
    - omap_drmif.h
    - am57xx-evm-cmem.dtsi (arch/arm/boot/dts/am57xx-evm-cmem.dtsi)

    kmscube.zip

  • Any input on this?
  • Hi Aupers,

    I am able to replicate the issue. We are still investigating the leak. Their was one potential leak found in EGL but that hasn't yet solve the problem with your sample test application. This week Thursday and Friday is holiday in US. So please expect response on progress made next week.
  • Hi Aupers,

    I have shared the SGX UM binaries with fix for memory leak with local FAE. He will pass it on to you. Please let me know if it resolves the issue at your end.

    We will get the fix officially available in upcoming Processor SDK 4.2 release.

    Regards,
    Manisha