hjimbens
Posts: 86
Joined: Fri May 24, 2013 9:05 am

Re: Span images/videos across two monitors 3840x1080

Thu Mar 26, 2020 7:32 pm

Thank you for your replies 6by9 and dividuum. I will try to explain in more detail what I am seeing. Below is my code that tries to create a GL texture from a vcsm_handle:

Code: Select all

GLuint
GetTextureForVcsmHandle (EGLDisplay inDisplay, int inVcsmHandle, int inWidth, int inHeight)
{
    static const char* sAttrName[] = {
        "EGL_LINUX_DRM_FOURCC_EXT",
        "EGL_DMA_BUF_PLANE0_FD_EXT",
        "EGL_DMA_BUF_PLANE0_OFFSET_EXT",
        "EGL_DMA_BUF_PLANE0_PITCH_EXT",
        "EGL_DMA_BUF_PLANE1_FD_EXT",
        "EGL_DMA_BUF_PLANE1_OFFSET_EXT",
        "EGL_DMA_BUF_PLANE1_PITCH_EXT",
        "EGL_DMA_BUF_PLANE2_FD_EXT",
        "EGL_DMA_BUF_PLANE2_OFFSET_EXT",
        "EGL_DMA_BUF_PLANE2_PITCH_EXT",
    };
    static const char* sAttrName2[] = {
        "EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT",
        "EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT",
        "EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT",
        "EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT",
        "EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT",
        "EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT",
    };
    static const char* sAttrName3[] = {
        "EGL_HEIGHT",
        "EGL_WIDTH",
    };

    static int sEGLDebugAttribList[] = {
        EGL_DEBUG_MSG_CRITICAL_KHR, EGL_TRUE,
        EGL_DEBUG_MSG_ERROR_KHR, EGL_TRUE,
        EGL_DEBUG_MSG_WARN_KHR, EGL_TRUE,
        EGL_DEBUG_MSG_INFO_KHR, EGL_TRUE,
        EGL_NONE, 0
    };
    PFNEGLDEBUGMESSAGECONTROLKHRPROC peglDebugMessageControlKHR = (PFNEGLDEBUGMESSAGECONTROLKHRPROC)eglGetProcAddress ("eglDebugMessageControlKHR");
    if (!(peglDebugMessageControlKHR != 0)) {
        printf ("failed to eglGetProcAddress eglDebugMessageControlKHR\n");
    } else {
        peglDebugMessageControlKHR (sEGLDebugCallback, sEGLDebugAttribList);
    }

    GLuint theTexture = 0;
    int theFd = vcsm_export_dmabuf (inVcsmHandle);
    uint32_t pitches[4] = { 0 };
    uint32_t offsets[4] = { 0 };
    uint64_t modifiers[4] = { 0 };
    pitches[0] = inWidth;
    modifiers[0] = DRM_FORMAT_MOD_BROADCOM_SAND128_COL_HEIGHT(get_sand_column_pitch(inHeight));
    pitches[1] = pitches[0];
    modifiers[1] = modifiers[0];
    offsets[1] = 128 * (inHeight+32);  //ISP seems to produce an extra 16 lines of padding. Don't know why.

    EGLint attribs[50];
    int i = 0;
    #define SETATTRIB(x,y) attribs[i++] = x; attribs[i++] = y; printf ("attr %s: 0x%x\n", (x >= EGL_LINUX_DRM_FOURCC_EXT && x <= EGL_DMA_BUF_PLANE2_PITCH_EXT) ? sAttrName[x - EGL_LINUX_DRM_FOURCC_EXT] : ((x >= EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT && x <= EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT) ? sAttrName2[x - EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT] : ((x >= EGL_HEIGHT && x <= EGL_WIDTH) ? sAttrName3[x - EGL_HEIGHT] : "EGL_NONE")), y);


    SETATTRIB (EGL_WIDTH, inWidth);
    SETATTRIB (EGL_HEIGHT, inHeight);
    unsigned int fourcc = mmal_encoding_to_drm_fourcc (MMAL_ENCODING_YUVUV128);
    printf("FB fourcc %c%c%c%c\n", fourcc, fourcc >> 8, fourcc >> 16, fourcc >> 24);
    SETATTRIB (EGL_LINUX_DRM_FOURCC_EXT, fourcc);
    for (int j = 0 ; j < 3 ; j++) {
        if (pitches[j]) {
            SETATTRIB (EGL_DMA_BUF_PLANE0_FD_EXT + j*(EGL_DMA_BUF_PLANE1_FD_EXT - EGL_DMA_BUF_PLANE0_FD_EXT), theFd);
            SETATTRIB (EGL_DMA_BUF_PLANE0_OFFSET_EXT + j*(EGL_DMA_BUF_PLANE1_OFFSET_EXT - EGL_DMA_BUF_PLANE0_OFFSET_EXT), offsets[j]);
            SETATTRIB (EGL_DMA_BUF_PLANE0_PITCH_EXT + j*(EGL_DMA_BUF_PLANE1_PITCH_EXT - EGL_DMA_BUF_PLANE0_PITCH_EXT), pitches[j]);
            if (modifiers[j]) {
                SETATTRIB (EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT + j*(EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT - EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT), modifiers[j] & 0xFFFFFFFF);
                SETATTRIB (EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT + j*(EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT - EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT), modifiers[j] >> 32);
            }
        }
    }
    SETATTRIB (EGL_NONE, 0);

    if (!(peglCreateImageKHR != 0)) {
        peglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC)eglGetProcAddress ("eglCreateImageKHR");
        if (!(peglCreateImageKHR != 0)) printf ("failed to eglGetProcAddress eglCreateImageKHR\n");
        peglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC)eglGetProcAddress ("eglDestroyImageKHR");
        if (!(peglDestroyImageKHR != 0)) printf ("failed to eglGetProcAddress eglDestroyImageKHR\n");
        pglEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)eglGetProcAddress ("glEGLImageTargetTexture2DOES");
        if (!(pglEGLImageTargetTexture2DOES != 0)) printf ("failed to eglGetProcAddress glEGLImageTargetTexture2DOES\n");
    }
    if (peglCreateImageKHR != 0) {
        // now create a texture corresponding to the dumb buffer
        EGLImage theImage = peglCreateImageKHR (inDisplay, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attribs);
        if (!theImage) {
            printf("Failed to import fd %d, fourcc %c%c%c%c, error 0x%x\n", theFd, fourcc, fourcc >> 8, fourcc >> 16, fourcc >> 24, eglGetError ());
            for (int j = 0 ; j < 3 ; j++) {
                if (pitches[j]) {
                    printf ("plane %d: fd %d offset %d pitch %d modifiers %llx\n", j, theFd, offsets[j], pitches[j], modifiers[j]);
                }
            }
        } else {
            glGenTextures (1, &theTexture);
            glBindTexture (GL_TEXTURE_EXTERNAL_OES, theTexture);
            glTexParameteri (GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
            glTexParameteri (GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
            pglEGLImageTargetTexture2DOES (GL_TEXTURE_EXTERNAL_OES, theImage);
            peglDestroyImageKHR (inDisplay, theImage);
        }
    }
    close (theFd);
    return theTexture;
}
Actually most of it is copied or at least very heavily inspired by https://github.com/6by9/drm_mmal.
The output that I get is

Code: Select all

attr EGL_WIDTH: 0x280
attr EGL_HEIGHT: 0x168
FB fourcc NV12
attr EGL_LINUX_DRM_FOURCC_EXT: 0x3231564e
attr EGL_DMA_BUF_PLANE0_FD_EXT: 0x19
attr EGL_DMA_BUF_PLANE0_OFFSET_EXT: 0x0
attr EGL_DMA_BUF_PLANE0_PITCH_EXT: 0x280
attr EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT: 0x25004
attr EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT: 0x7000000
attr EGL_DMA_BUF_PLANE1_FD_EXT: 0x19
attr EGL_DMA_BUF_PLANE1_OFFSET_EXT: 0xc400
attr EGL_DMA_BUF_PLANE1_PITCH_EXT: 0x280
attr EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT: 0x25004
attr EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT: 0x7000000
attr EGL_NONE: 0x0
EGL error: 0x3009, command eglCreateImageKHR, type 13242, thread (null), object (null), message dri2_create_image_khr_texture, EGL_BAD_MATCH: Arguments are inconsistent (for example, a valid context requires buffers not supplied by a valid surface).
Failed to import fd 25, fourcc NV12, error 0x3009
plane 0: fd 25 offset 0 pitch 640 modifiers 700000000025004
plane 1: fd 25 offset 50176 pitch 640 modifiers 700000000025004
So the call eglCreateImageKHR (inDisplay, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attribs) fails and it does not get past the verification of the parameters.
Looking at the mesa code that is not really surprising. In particular the code in https://gitlab.freedesktop.org/mesa/mes ... ri2.c#L842 does not seem to know DRM_FORMAT_MOD_BROADCOM_SAND128_COL_HEIGHT so it returns 0 for the number of planes.Then the test in https://gitlab.freedesktop.org/mesa/mes ... ri2.c#L891 fails and returns the bad_match error.

So it seems that it is not possible to get the decoded frame directly into a texture. Maybe it is possible by converting the format with the mmal isp, but that would probably cost a lot of performance. Or am I looking at the wrong sources? Or am I missing something altogether?

The file that I am using is 8 bit.

hjimbens
Posts: 86
Joined: Fri May 24, 2013 9:05 am

Re: Span images/videos across two monitors 3840x1080

Sun Mar 29, 2020 2:06 pm

I finally managed to get the SAND frames into GL textures. The trick is to not try to get it into a single texture with eglCreateImageKHR, but to create a separate texture for each SAND strip. So for a 3840x2160 4K video you use 30 128x2160 textures. I don't have to many test files, but full hd files and a 10s 4K video at 24fps played just fine. A 4K video at 60fps was a bit too much. I am not sure the 4K 60fps would have played, had I found a way to import the frames into a single texture. One bottle neck appears to be that any linear texture created with eglCreateImageKHR has to be blitted to a tiled (shadow-) texture before display: https://gitlab.freedesktop.org/mesa/mes ... rce.c#L944

Return to “Graphics, sound and multimedia”