Page 1 of 1

Pi3/OpenGL ES with vc4-kms-v3d driver

Posted: Sun Feb 23, 2020 1:01 pm
by oleg11
Hi, All!

I am going to use CM3+ module. I am planning to attach display using DSI (not a standard display - the same as CutiePi use). As far as I know I need vc4-kms-v3d driver to do it. So, I decided to try how it performs with RPi 3A+ and HDMI display I had by hand. I need OpenGL ES 2.0 full screen rendering without X. But first of all I need just to initialize all the things.

So, here is the simple test program (it is from this topic viewtopic.php?t=243707 with minimal changes):

Code: Select all

// gcc -o drm-gbm drm-gbm-mod.c -ldrm -lgbm -lEGL -lGL -I/usr/include/libdrm

//----------------------------------------------------------------------
//--------  Trying to get OpenGL ES screen on RPi4 without X
//--------  based on drm-gbm https://github.com/eyelash/tutorials/blob/master/drm-gbm.c
//--------  and kmscube https://github.com/robclark/kmscube
//--------  pik33@o2.pl
//----------------------------------------------------------------------

#include <xf86drm.h>
#include <xf86drmMode.h>
#include <gbm.h>
#include <EGL/egl.h>
#include <GL/gl.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <assert.h>

#define EXIT(msg)         \
   {                      \
      fputs(msg, stderr); \
      exit(EXIT_FAILURE); \
   }

// global variables declarations

static int device;
static drmModeRes *resources;
static drmModeConnector *connector;
static uint32_t connector_id;
static drmModeEncoder *encoder;
static drmModeModeInfo mode_info;
static drmModeCrtc *crtc;
static struct gbm_device *gbm_device;
static EGLDisplay display;
static EGLContext context;
static struct gbm_surface *gbm_surface;
static EGLSurface egl_surface;
EGLConfig config;
EGLint num_config;
EGLint count = 0;
EGLConfig *configs;
int config_index;
int i;

static struct gbm_bo *previous_bo = NULL;
static uint32_t previous_fb;

static EGLint attributes[] = {
    EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
    EGL_RED_SIZE, 8,
    EGL_GREEN_SIZE, 8,
    EGL_BLUE_SIZE, 8,
    EGL_ALPHA_SIZE, 0,
    EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
    EGL_NONE};

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

struct gbm_bo *bo;
uint32_t handle;
uint32_t pitch;
int32_t fb;
uint64_t modifier;

static drmModeConnector *find_connector(drmModeRes *resources)
{

   for (i = 0; i < resources->count_connectors; i++)
   {
      drmModeConnector *connector = drmModeGetConnector(device, resources->connectors[i]);
      if (connector->connection == DRM_MODE_CONNECTED)
      {
         return connector;
      }
      drmModeFreeConnector(connector);
   }
   return NULL; // if no connector found
}

static drmModeEncoder *find_encoder(drmModeRes *resources, drmModeConnector *connector)
{

   if (/*connector->encoder_id */1)
   {
      return drmModeGetEncoder(device, connector->encoder_id);
   }
   return NULL; // if no encoder found
}

static void swap_buffers()
{

   eglSwapBuffers(display, egl_surface);
   bo = gbm_surface_lock_front_buffer(gbm_surface);
   handle = gbm_bo_get_handle(bo).u32;
   pitch = gbm_bo_get_stride(bo);
   drmModeAddFB(device, mode_info.hdisplay, mode_info.vdisplay, 24, 32, pitch, handle, &fb);
   drmModeSetCrtc(device, crtc->crtc_id, fb, 0, 0, &connector_id, 1, &mode_info);
   if (previous_bo)
   {
      drmModeRmFB(device, previous_fb);
      gbm_surface_release_buffer(gbm_surface, previous_bo);
   }
   previous_bo = bo;
   previous_fb = fb;
}

static void draw(float progress)
{

   glClearColor(1.0f - progress, progress, 0.0, 1.0);
   glClear(GL_COLOR_BUFFER_BIT);
   swap_buffers();
}

static int match_config_to_visual(EGLDisplay egl_display, EGLint visual_id, EGLConfig *configs, int count)
{

   EGLint id;
   for (i = 0; i < count; ++i)
   {
      if (!eglGetConfigAttrib(egl_display, configs[i], EGL_NATIVE_VISUAL_ID, &id))
         continue;
      if (id == visual_id)
         return i;
   }
   return -1;
}

int main()
{

   device = open("/dev/dri/card0", O_RDWR);
   assert(device != 0);
   
   resources = drmModeGetResources(device);
   assert(resources != NULL);
   
   connector = find_connector(resources);
   assert(connector != NULL);

   printf("Modes list:\n------------------\n");
   for(int i = 0; i < connector->count_modes; i++)
   {
      printf("Mode %d: %s\n", i, connector->modes[i].name);
   }

   printf("\nSelect mode (0..%d):", connector->count_modes);
   int mode_num;
   scanf("%d", &mode_num);
   connector_id = connector->connector_id;
   mode_info = connector->modes[mode_num];

   encoder = find_encoder(resources, connector);
   assert(encoder != NULL);
   
   crtc = drmModeGetCrtc(device, encoder->crtc_id);
   assert(crtc != 0);

   drmModeFreeEncoder(encoder);
   drmModeFreeConnector(connector);
   drmModeFreeResources(resources);
   
   gbm_device = gbm_create_device(device);
   assert(gbm_device != 0);
   gbm_surface = gbm_surface_create(gbm_device, mode_info.hdisplay, mode_info.vdisplay, GBM_FORMAT_XRGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
   assert(gbm_surface != NULL);
   display = eglGetDisplay(gbm_device);
   eglInitialize(display, NULL, NULL);
   eglBindAPI(EGL_OPENGL_API);
   eglGetConfigs(display, NULL, 0, &count);
   configs = malloc(count * sizeof *configs);
   eglChooseConfig(display, attributes, configs, count, &num_config);
   config_index = match_config_to_visual(display, GBM_FORMAT_XRGB8888, configs, num_config);
   context = eglCreateContext(display, configs[config_index], EGL_NO_CONTEXT, context_attribs);
   egl_surface = eglCreateWindowSurface(display, configs[config_index], gbm_surface, NULL);
   free(configs);
   eglMakeCurrent(display, egl_surface, egl_surface, context);

   for (i = 0; i < 600; i++)
      draw(i / 600.0f);

   drmModeSetCrtc(device, crtc->crtc_id, crtc->buffer_id, crtc->x, crtc->y, &connector_id, 1, &crtc->mode);
   drmModeFreeCrtc(crtc);
   if (previous_bo)
   {
      drmModeRmFB(device, previous_fb);
      gbm_surface_release_buffer(gbm_surface, previous_bo);
   }
   eglDestroySurface(display, egl_surface);
   gbm_surface_destroy(gbm_surface);
   eglDestroyContext(display, context);
   eglTerminate(display);
   gbm_device_destroy(gbm_device);

   close(device);
   return 0;
}
It works flawlessly with vc4-fkms-v3d , but it does not work with vc4-kms-v3d I am interested in. The problem with the 'connector->encoder_id' field - it is always zero. The OpenGL ES initialization part is ok (I checked it separately down to eglCreateWindowSurface, which needs gbm_surface I can not get because of the above problem).

Another wrong thing is the reported modes list - using the vc4-fkms-v3d there are 1920x1200 (the resolution of the connected display) and 1600x1200 modes additionally to the 21 similar (with the vc4-kms-v3d) lower resolution modes.

Does anybody have any ideas?

Here is the output of some command (do not know if it will be usefull)

Code: Select all

ls /dev/dri
by-path  card0  renderD128

Code: Select all

uname -a
Linux raspberrypi 4.19.102-v7+ #1295 SMP Thu Feb 6 15:43:59 GMT 2020 armv7l GNU/Linux

Code: Select all

vcgencmd version
Feb 12 2020 12:38:08
Copyright (c) 2012 Broadcom
version 53a54c770c493957d99bf49762dfabc4eee00e45 (clean) (release) (start)
All the best!
Oleg