Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PI4 support? #3

Closed
ArtArt0 opened this issue Aug 19, 2019 · 20 comments
Closed

PI4 support? #3

ArtArt0 opened this issue Aug 19, 2019 · 20 comments

Comments

@ArtArt0
Copy link

ArtArt0 commented Aug 19, 2019

Hi! - I just saw, the pi4 support todo. Will it work on Pi4?

@matusnovak
Copy link
Owner

I don't see a reason why it should not work, but I have not tested it yet, because I don't have a Raspberry Pi 4. I should have one this week and will give it a try.

@ArtArt0
Copy link
Author

ArtArt0 commented Aug 20, 2019

I do not see neither, but i have and i think it wont work, because of my code - similar to yours - uses dispmanx with egl and pi4 has no full kms driver...

@matusnovak
Copy link
Owner

I am not losing hope yet.

Unfortunately it seems that I won't receive my Raspberry Pi 4 before this weekend, so I'll get back to you the following next week.

@ArtArt0
Copy link
Author

ArtArt0 commented Aug 23, 2019

Me neither :)

@matusnovak
Copy link
Owner

@ArtArt0 Raspberry Pi 4 is already here, but it does not like my older SD card for some reason, need to buy a new one. I should be able to finally test it tomorrow.

@ArtArt0
Copy link
Author

ArtArt0 commented Aug 28, 2019

Ok, thanx, I am still waiting... :)

@matusnovak
Copy link
Owner

matusnovak commented Aug 28, 2019

@ArtArt0

I wasn't able to get anywhere, there is no full kms and I can't find any more info on that. I have tried following many different posts about running EGL via DRM/GBM library. There is some discussion about it here: https://www.raspberrypi.org/forums/viewtopic.php

Could you try the code below? You might have a better luck than me. Try also chaing the /dev/dri/card1 to /dev/dri/card0, maybe it will do something, but it didn't work for me though.

The code is from this post: https://www.raspberrypi.org/forums/viewtopic.php?t=243707#p1499181 I have copy pasted the code below with an extra NULL check so you don't get segmentation fault.

Additionally, someone has said that they had success with https://gitlab.freedesktop.org/mesa/kmscube (I have tried it, no luck).

The code:

// Compile as:
// gcc -o drm-gbm drm-gbm-mod.c -g -O0 -ldrm -lgbm -lEGL -lGL -I/usr/include/libdrm

// Extra dependencies needed:
// sudo apt-get install libegl1-mesa-dev libgbm-dev

//----------------------------------------------------------------------
//--------  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>

#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) {
        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/card1", O_RDWR);
    resources = drmModeGetResources (device);
    if (resources == NULL) {
        printf("drmModeGetResources returned NULL\n");
        return 1;
    }
    connector = find_connector (resources);
    connector_id = connector->connector_id;
    mode_info = connector->modes[0];
    encoder = find_encoder (resources, connector);
    crtc = drmModeGetCrtc (device, encoder->crtc_id);
    drmModeFreeEncoder (encoder);
    drmModeFreeConnector (connector);
    drmModeFreeResources (resources);
    gbm_device = gbm_create_device (device);
    gbm_surface = gbm_surface_create (gbm_device, mode_info.hdisplay, mode_info.vdisplay, GBM_FORMAT_XRGB8888, GBM_BO_USE_SCANOUT|GBM_BO_USE_RENDERING);
    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;
}

@naluhh
Copy link

naluhh commented Sep 5, 2019

Jumping on this. @matusnovak Your code run without any issue.

@matusnovak
Copy link
Owner

@naluhh Thank you for testing it out. I am probably doing something wrong on my side (maybe because I am using it in a headless mode with no screen output). Once I figure it out, I will create a new triangle_rpi4.c file on the master branch with the necessary changes.

@matusnovak
Copy link
Owner

@ArtArt0 Done.

See the triangle_rpi4.c file in this repository and the relevant instructions in the README file.

@ArtArt0
Copy link
Author

ArtArt0 commented Jan 22, 2020

Thanks! - I just did it in my code using your and your used codes, and I found an interesting thing:

If I try to use (just link the corresponded lib directory) bcm_host.h, the pi4 code just does not work anymore, even if I am not call bcm_host_init()...

What is happening?

@matusnovak
Copy link
Owner

@ArtArt0

I don't exactly know what bcm_host.h does but I think it sets some variables specific to the Broadcom (BCM = Broadcom) processor that Raspberry Pi 1, 2, and 3 use.

The Raspberry Pi 4 uses a different CPU, therefore a different GPU, so the triangle_rpi4.c code uses the GBM and DRM libraries.

I assume using bcm_host.h causes hardware compatibility issues.

If you need to import bcm_host.h I would suggest to do that after any relevant EGL code.

@ArtArt0
Copy link
Author

ArtArt0 commented Jan 22, 2020

I dont use bcm_host.h, just linked the corresponded lib path in!

@matusnovak
Copy link
Owner

@ArtArt0 What does your gcc linking command look like?

@ArtArt0
Copy link
Author

ArtArt0 commented Jan 22, 2020

Add gcc the following: -L/opt/vc/lib

The result is: * failed to add service - already in use?

@matusnovak
Copy link
Owner

matusnovak commented Jan 22, 2020

@ArtArt0

You should be not using /opt/vc/lib on Raspberry Pi 4. The vc stands for VideoCore library which is used only in Raspberry Pi 1, 2, and 3.

Previous Pi's used a non-standard mechanism of getting EGL onto a display (dispmanx).
When using kms/fkms (pi4 only supports fkms) you can't use that and need do this the standard linux way.

This is a useful thread where these methods are discussed:
https://www.raspberrypi.org/forums/viewtopic.php?f=68&t=243611

Source: raspberrypi/firmware#1171 (comment)

There is more about that also here: libretro/RetroArch#9727

So, to get the triangle_rpi4.c code running, you need to compile it as:

gcc -o triangle_rpi4 triangle_rpi4.c -ldrm -lgbm -lEGL -lGLESv2 \
  -I/usr/include/libdrm -I/usr/include/GLES2

Without using the /opt/vc/lib directory. The /opt/vc/lib contains EGL and GLESv2 that are specific to the Broadcom CPU/GPU and VideoCore. You need to link to the correct EGL and GLESv2 libraries installed via sudo apt-get install libegl1-mesa-dev libgbm-dev libgles2-mesa-dev. I assume that when you add -L/opt/vc/lib the GCC will link to the incorrect libraries.

And you may need to ensure that /boot/config.txt contains dtoverlay=vc4-fkms-v3d.

@matusnovak
Copy link
Owner

Also, similar issue to the failed to ass service - already in use? error is here: #1 (But that's Raspberry Pi 3 related).

@ArtArt0
Copy link
Author

ArtArt0 commented Jan 22, 2020

Ok, but on Pi4 I can not use bcm_host.h, can I?

@matusnovak
Copy link
Owner

No you should not, it's not compatible with Pi4.

@ArtArt0
Copy link
Author

ArtArt0 commented Jan 22, 2020

Thanks Matus! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants