bool EGLInteropResource::map(IDirect3DSurface9* surface, GLuint tex, int w, int h, int)
{
    D3DSURFACE_DESC dxvaDesc;
    surface->GetDesc(&dxvaDesc);
    if (!ensureSurface(w, h)) {
        releaseEGL();
        releaseDX();
        return false;
    }
    DYGL(glBindTexture(GL_TEXTURE_2D, tex));
    const RECT src = { 0, 0, w, h};
    if (SUCCEEDED(d3ddev->StretchRect(surface, &src, dx_surface, NULL, D3DTEXF_NONE))) {
        if (dx_query) {
            // Flush the draw command now. Ideally, this should be done immediately before the draw call that uses the texture. Flush it once here though.
            dx_query->Issue(D3DISSUE_END);
            // ensure data is copied to egl surface. Solution and comment is from chromium
            // The DXVA decoder has its own device which it uses for decoding. ANGLE has its own device which we don't have access to.
            // The above code attempts to copy the decoded picture into a surface which is owned by ANGLE.
            // As there are multiple devices involved in this, the StretchRect call above is not synchronous.
            // We attempt to flush the batched operations to ensure that the picture is copied to the surface owned by ANGLE.
            // We need to do this in a loop and call flush multiple times.
            // We have seen the GetData call for flushing the command buffer fail to return success occassionally on multi core machines, leading to an infinite loop.
            // Workaround is to have an upper limit of 10 on the number of iterations to wait for the Flush to finish.
            int k = 0;
            while ((dx_query->GetData(NULL, 0, D3DGETDATA_FLUSH) == FALSE) && ++k < 10) {
                Sleep(1);
            }
        }
        eglBindTexImage(egl->dpy, egl->surface, EGL_BACK_BUFFER);
    }
    DYGL(glBindTexture(GL_TEXTURE_2D, 0));
    return true;
}
EGLInteropResource::~EGLInteropResource()
{
    releaseEGL();
    if (egl) {
        delete egl;
        egl = NULL;
    }
    SafeRelease(&dx_query);
}
Exemple #3
0
EGLInteropResource::~EGLInteropResource()
{
    releaseEGL();
    if (egl) {
        delete egl;
        egl = NULL;
    }
    SafeRelease(&query9);
    SafeRelease(&surface9_nv12);
    SafeRelease(&texture9_nv12);
    SafeRelease(&surface9);
    SafeRelease(&texture9);
    SafeRelease(&device9);
    SafeRelease(&d3d9);
    if (dll9)
        FreeLibrary(dll9);
}
Exemple #4
0
bool EGLInteropResource::ensureResource(int w, int h, int W, int H, GLuint tex)
{
    TexRes &r = res[0];// 1 NV12 texture
    if (ensureD3D9CUDA(w, h, W, H) && ensureD3D9EGL(w, h)) {
        r.texture = tex;
        r.w = w;
        r.h = h;
        r.W = W;
        r.H = H;
        return true;
    }
    releaseEGL();
    //releaseDX();
    SafeRelease(&query9);
    SafeRelease(&surface9);
    SafeRelease(&texture9);
    SafeRelease(&surface9_nv12);
    SafeRelease(&texture9_nv12);
    return false;
}
bool EGLInteropResource::ensureSurface(int w, int h) {
    if (egl->surface && width == w && height == h)
        return true;
    releaseEGL(); //
    egl->dpy = eglGetCurrentDisplay();
    qDebug("EGL version: %s, client api: %s", eglQueryString(egl->dpy, EGL_VERSION), eglQueryString(egl->dpy, EGL_CLIENT_APIS));
    EGLint cfg_attribs[] = {
        EGL_RED_SIZE, 8,
        EGL_GREEN_SIZE, 8,
        EGL_BLUE_SIZE, 8,
        EGL_ALPHA_SIZE, 8, //
        EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE, //remove?
        EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
        EGL_NONE
    };
    EGLint nb_cfgs;
    EGLConfig egl_cfg;
    if (!eglChooseConfig(egl->dpy, cfg_attribs, &egl_cfg, 1, &nb_cfgs)) {
        qWarning("Failed to create EGL configuration");
        return false;
    }
    // check extensions
    QList<QByteArray> extensions = QByteArray(eglQueryString(egl->dpy, EGL_EXTENSIONS)).split(' ');
    // ANGLE_d3d_share_handle_client_buffer will be used if possible
    // TODO: strstr is enough
    const bool kEGL_ANGLE_d3d_share_handle_client_buffer = extensions.contains("EGL_ANGLE_d3d_share_handle_client_buffer");
    const bool kEGL_ANGLE_query_surface_pointer = extensions.contains("EGL_ANGLE_query_surface_pointer");
    if (!kEGL_ANGLE_d3d_share_handle_client_buffer && !kEGL_ANGLE_query_surface_pointer) {
        qWarning("EGL extension 'kEGL_ANGLE_query_surface_pointer' or 'ANGLE_d3d_share_handle_client_buffer' is required!");
        return false;
    }
    GLint has_alpha = 1; //QOpenGLContext::currentContext()->format().hasAlpha()
    eglGetConfigAttrib(egl->dpy, egl_cfg, EGL_BIND_TO_TEXTURE_RGBA, &has_alpha); //EGL_ALPHA_SIZE
    qDebug("choose egl display:%p config: %p/%d, has alpha: %d", egl->dpy, egl_cfg, nb_cfgs, has_alpha);
    EGLint attribs[] = {
        EGL_WIDTH, w,
        EGL_HEIGHT, h,
        EGL_TEXTURE_FORMAT, has_alpha ? EGL_TEXTURE_RGBA : EGL_TEXTURE_RGB,
        EGL_TEXTURE_TARGET, EGL_TEXTURE_2D,
        EGL_NONE
    };

    HANDLE share_handle = NULL;
    if (!kEGL_ANGLE_d3d_share_handle_client_buffer && kEGL_ANGLE_query_surface_pointer) {
        EGL_ENSURE((egl->surface = eglCreatePbufferSurface(egl->dpy, egl_cfg, attribs)) != EGL_NO_SURFACE, false);
        qDebug("pbuffer surface: %p", egl->surface);
        PFNEGLQUERYSURFACEPOINTERANGLEPROC eglQuerySurfacePointerANGLE = reinterpret_cast<PFNEGLQUERYSURFACEPOINTERANGLEPROC>(eglGetProcAddress("eglQuerySurfacePointerANGLE"));
        if (!eglQuerySurfacePointerANGLE) {
            qWarning("EGL_ANGLE_query_surface_pointer is not supported");
            return false;
        }
        EGL_ENSURE(eglQuerySurfacePointerANGLE(egl->dpy, egl->surface, EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, &share_handle), false);
    }
    releaseDX();
    // _A8 for a yuv plane
    /*
     * d3d resource share requires windows >= vista: https://msdn.microsoft.com/en-us/library/windows/desktop/bb219800(v=vs.85).aspx
     * from extension files:
     * d3d9: level must be 1, dimensions must match EGL surface's
     * d3d9ex or d3d10:
     */
    DX_ENSURE_OK(d3ddev->CreateTexture(w, h, 1,
                                        D3DUSAGE_RENDERTARGET,
                                        has_alpha ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8,
                                        D3DPOOL_DEFAULT,
                                        &dx_texture,
                                        &share_handle) , false);
    DX_ENSURE_OK(dx_texture->GetSurfaceLevel(0, &dx_surface), false);

    if (kEGL_ANGLE_d3d_share_handle_client_buffer) {
        // requires extension EGL_ANGLE_d3d_share_handle_client_buffer
        // egl surface size must match d3d texture's
        // d3d9ex or d3d10 is required
        EGL_ENSURE((egl->surface = eglCreatePbufferFromClientBuffer(egl->dpy, EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, share_handle, egl_cfg, attribs)), false);
        qDebug("pbuffer surface from client buffer: %p", egl->surface);
    }
    width = w;
    height = h;
    return true;
}