eglCreatePBufferFromClientBuffer not creating

Hi All,

Ques (1) . I am trying to create the egl surface using eglCreatePBufferFromClientBuffer .
Following are the list of steps that I am doing to get the same.
(I have valid EGLDisplay and have initialized egl and eglBindAPI has been called)
1). Create VGImage handle using vgCreateImage into vgImageHandle
2). eglChooseConfig for pbufferFromClientBuffer into pbufferConfig
3). egl_surface = eglCreatePBufferFromClientBuffer (egl_display,pbufferConfig,EGL_OPENVG_IMAGE,(EGLClientBuffer)vgImageHandle,pbufferConfig,NULL).

But when I debug it, I am getting egl_surface value as 0x0. Interestingly my ASSERT_EGL_NO_ERROR() also does not give me any error. :?

We have AmanithVG as our backend.
Our EGL version is 1.4 Gallium

Ques (2). The thought behind Ques 1 is just out of experiment.

  • I am trying to use vg api’s like vguRect/vgDrawPath and trying to draw it on the egl surface created using eglCreatePBufferFromClientBuffer .
  • I would then be trying to read the pixels into my pre-allocated buffer using vgReadPixels.
    I am not very sure whether we can read the pixels like this. But aim is to get the pixel data for the rectangle which vguRect/vgDrawPath might have created over pbufferFromClientBuffer surface.

Any kind of feedback/help/suggestions/answers would be great.

PS: Being new to this EGL/OpenVG stuff, I might have missed out on providing important information for the problem statement, which when pointed out - I would more than happy to share :oops:

Thanks in advance.

AmanithVG GLE does not support “rendering on VGImage”, so eglCreatePBufferFromClientBuffer, if used in conjunction with a vgImageHandle created through AmanithVG, will fail (as you have experimented).
Anyway, if your intent is to draw OpenVG stuff onto an offline buffer (e.g. an EGL pbuffer), you can do it: just ensure to make the pbuffer surface current.


typedef struct _EGLState {
    EGLSurface eglSurface;
    void *vgSurface;
    EGLContext eglContext;
    void *vgContext;
} EGLState;

EGLBoolean createWindowSurface(EGLState *state, EGLDisplay eglDisplay, EGLConfig eglConfig) {

    // ensure the specified eglConfig was chosen (by eglChooseConfig) specifying
    // EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
    // EGL_BUFFER_SIZE, 32, EGL_DEPTH_SIZE, 24, EGL_STENCIL_SIZE, 8
    state->eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig, ...);
    if (state->eglSurface != EGL_NO_SURFACE) {
        EGLint surfaceWidth, surfaceHeight;
        // get window surface dimensions
        eglQuerySurface(eglDisplay, state->eglSurface, EGL_WIDTH, &surfaceWidth);
        eglQuerySurface(eglDisplay, state->eglSurface, EGL_HEIGHT, &surfaceHeight);
        // AmanithVG GLE surfaces contains just some internal data and a reference to a
        // GL texture used to implement OpenVG alpha mask feature 
        state->vgSurface = vgPrivSurfaceCreateMZT(surfaceWidth, surfaceHeight, VG_FALSE, VG_TRUE);
        return EGL_TRUE;
    }
    else
        return EGL_FALSE;
}

EGLBoolean createPbufferSurface(EGLState *state, EGLDisplay eglDisplay, EGLConfig eglConfig, EGLint width, EGLint height) {

    EGLint surfAttribs[] = {
        EGL_WIDTH, width,
        EGL_HEIGHT, height,
        EGL_NONE
    };

    // ensure the specified eglConfig was chosen (by eglChooseConfig) specifying
    // EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
    // EGL_BUFFER_SIZE, 32, EGL_DEPTH_SIZE, 24, EGL_STENCIL_SIZE, 8
    state->eglSurface = eglCreatePbufferSurface(eglDisplay, eglConfig, surfAttribs);
    if (state->eglSurface != EGL_NO_SURFACE) {
        EGLint surfaceWidth, surfaceHeight;
        // get pbuffer surface dimensions
        eglQuerySurface(eglDisplay, state->eglSurface, EGL_WIDTH, &surfaceWidth);
        eglQuerySurface(eglDisplay, state->eglSurface, EGL_HEIGHT, &surfaceHeight);
        // AmanithVG GLE surfaces contains just some internal data and a reference to a
        // GL texture used to implement OpenVG alpha mask feature 
        state->vgSurface = vgPrivSurfaceCreateMZT(surfaceWidth, surfaceHeight, VG_FALSE, VG_TRUE);
        return EGL_TRUE;
    }
    else
        return EGL_FALSE;
}

EGLBoolean createContext(EGLState *state, EGLDisplay eglDisplay, EGLConfig eglConfig) {

    state->eglContext = eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, NULL);
    if (state->eglContext != EGL_NO_CONTEXT) {
        // AmanithVG GLE contexts contains the whole OpenVG state (e.g. stroking parameters, ...)
        // and references to GL textures (as well vertex buffers) used to implement OpenVG paint
        // types (and drawing primitives).
        state->vgContext = vgPrivContextCreateMZT(NULL);
        return EGL_TRUE;
    }
    else
        return EGL_FALSE;
}

EGLBoolean makeCurrent(EGLDisplay eglDisplay, EGLState *currentState, EGLState *newState) {

    if (!currentState) {
        if (newState) {
            if (eglMakeCurrent(eglDisplay, newState->eglSurface, newState->eglSurface, newState->eglContext) == EGL_TRUE) {
                // now that the underlying GL system has made context and surface current, we can call
                // AmanithVG GLE vgPrivMakeCurrentMZT: the function itself gets some GL states, the list
                // of available GL extensions, and sets GL states and texture units in order to make them
                // work correctly with AmanithVG GLE
                vgPrivMakeCurrentMZT(newState->vgContext, newState->vgSurface);
                // exit with success
                return EGL_TRUE;
            }
            else
                return EGL_FALSE;
        }
        else
            // current and new state are NULL, so nothing to do
            return EGL_FALSE;
    }
    else {
        if (newState) {
            if (newState != currentState) {
                // we must deference AmanithVG GLE surface and context first, because some GL textures
                // or buffers can be destroyed if unuseful (and in order to destroy them correctly, the
                // GL context where they have been created must be still active)
                vgPrivMakeCurrentMZT(NULL, NULL);
                // now we can bind the new state
                if (eglMakeCurrent(eglDisplay, newState->eglSurface, newState->eglSurface, newState->eglContext) == EGL_TRUE) {
                    // now that the underlying GL system has made context and surface current, we can call
                    // AmanithVG GLE vgPrivMakeCurrentMZT: the function itself gets some GL states, the list of
                    // available GL extensions, and sets GL states and texture units in order to make them
                    // work correctly with AmanithVG GLE
                    vgPrivMakeCurrentMZT(newState->vgContext, newState->vgSurface);
                    // exit with success
                    return EGL_TRUE;
                }
                else
                    return EGL_FALSE;
            }
            else
                // current and new state are the same, so nothing to do
                return EGL_TRUE;
        }
        else {
            // we must deference AmanithVG GLE surface and context first, because some GL textures or
            // buffers can be destroyed if unuseful (and in order to destroy them correctly, the GL context
            // where they have been created must be still active)
            vgPrivMakeCurrentMZT(NULL, NULL);
            return eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
        }
    }
}

void swapBuffers(EGLDisplay eglDisplay, EGLSurface eglSurface) {

    eglSwapBuffers(eglDisplay, eglSurface);
    // this function grants AmanithVG GLE to work properly even on GLES systems with unpersistent
    // buffers (most mobile architectures does not have persistent depth buffers)
    vgPostSwapBuffersMZT();
}

After you make current a state, you can draw your stuff using OpenVG calls; then call swapBuffers(…) and read current surface pixels using the (slow, especially in the case of AmanithVG GLE) vgReadPixels function.
Of course, if you use AmanithVG SRE (instead of AmanithVG GLE), you can remove all those vgPriv* calls, because AmanithVG SRE includes an EGL 1.4 implementation too.

So, you can use the code above as follow (error checking and obvious parameters omitted):


EGLint attribListWindow[] = {
    EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
    EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
    EGL_BUFFER_SIZE, 32,
    EGL_DEPTH_SIZE, 24,
    EGL_STENCIL_SIZE, 8
    EGL_NONE
};

EGLint attribListPbuffer[] = {
    EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
    EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
    EGL_BUFFER_SIZE, 32,
    EGL_DEPTH_SIZE, 24,
    EGL_STENCIL_SIZE, 8
    EGL_NONE
};

EGLState windowState, pbufferState;

// basic initializations
eglDisplay = eglGetDisplay(...);
!eglInitialize(eglDisplay, &iMajorVersion, &iMinorVersion);
eglBindAPI(EGL_OPENGL_API);

// create state for a window surface
eglChooseConfig(eglDisplay, attribListWindow, &eglConfigWindow, 1, &iConfigs);
createWindowSurface(&windowState, eglDisplay, eglConfigWindow);
createContext(&windowState, eglDisplay, eglConfigWindow);

// create state for a pbuffer surface
eglChooseConfig(eglDisplay, attribListPbuffer, &eglConfigPbuffer, 1, &iConfigs);
createPbufferSurface(&pbufferState, eglDisplay, eglConfigPbuffer);
createContext(&pbufferState, eglDisplay, eglConfigPbuffer);

makeCurrent(eglDisplay, NULL, &windowState);
<draw your OpenVG stuff in the window surface>
swapBuffers(eglDisplay, windowState.eglSurface);

makeCurrent(eglDisplay, NULL, &pbufferState);
<draw your OpenVG stuff in the offline pbuffer surface>
vgReadPixels(...)

Feel free to contact me in private, if you need more details.
I think Khronos OpenVG forum is not the best place to talk about AmanithVG + Webkit EFL integration.