TInt CEGLGraphicsInterface::BindClientBuffer(TUint aBuffer)
    {
    // Save current context and surfaces
    iSavedContext = eglGetCurrentContext();
    iSavedDrawSurface = eglGetCurrentSurface(EGL_DRAW);
    iSavedReadSurface = eglGetCurrentSurface(EGL_READ);
    
    if ( eglMakeCurrent( iEglDisplay,  EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT ) == EGL_FALSE )
        {
        return MapEGLErrorCodeToSymbian(eglGetError());
        }

    const EGLint attribList2[] = {  EGL_NONE };
    iEglPbufSurface = eglCreatePbufferFromClientBuffer(iEglDisplay, EGL_OPENVG_IMAGE, (EGLClientBuffer)aBuffer,  iConfig, attribList2);
    
    if ( iEglPbufSurface == EGL_NO_SURFACE )
        {
        return MapEGLErrorCodeToSymbian(eglGetError());
        }

    if ( eglMakeCurrent( iEglDisplay,    iEglPbufSurface ,  iEglPbufSurface ,iEglContext ) == EGL_FALSE )
        {
        return MapEGLErrorCodeToSymbian(eglGetError());
        }
    return KErrNone;
    }
    EGLSurface createD3D11PBuffer(size_t width,
                                  size_t height,
                                  EGLint eglTextureFormat,
                                  EGLint eglTextureTarget,
                                  UINT sampleCount,
                                  UINT sampleQuality,
                                  UINT bindFlags,
                                  DXGI_FORMAT format)
    {
        EGLWindow *window  = getEGLWindow();
        EGLDisplay display = window->getDisplay();
        EGLConfig config   = window->getConfig();

        EGLint attribs[] = {
            EGL_TEXTURE_FORMAT, eglTextureFormat, EGL_TEXTURE_TARGET,
            eglTextureTarget,   EGL_NONE,         EGL_NONE,
        };

        ASSERT(mD3D11Device);
        ID3D11Texture2D *texture = nullptr;
        CD3D11_TEXTURE2D_DESC desc(format, static_cast<UINT>(width), static_cast<UINT>(height), 1,
                                   1, bindFlags);
        desc.SampleDesc.Count   = sampleCount;
        desc.SampleDesc.Quality = sampleQuality;
        EXPECT_TRUE(SUCCEEDED(mD3D11Device->CreateTexture2D(&desc, nullptr, &texture)));

        EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(display, EGL_D3D_TEXTURE_ANGLE,
                                                              texture, config, attribs);

        texture->Release();

        return pbuffer;
    }
    EGLSurface createPBuffer(size_t width,
                             size_t height,
                             EGLint eglTextureFormat,
                             EGLint eglTextureTarget,
                             UINT sampleCount,
                             UINT sampleQuality)
    {
        if (mD3D11Device)
        {
            return createD3D11PBuffer(
                width, height, eglTextureFormat, eglTextureTarget, sampleCount, sampleQuality,
                D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET, DXGI_FORMAT_R8G8B8A8_UNORM);
        }

        if (mD3D9Device)
        {
            EGLWindow *window  = getEGLWindow();
            EGLDisplay display = window->getDisplay();
            EGLConfig config   = window->getConfig();

            EGLint attribs[] = {
                EGL_TEXTURE_FORMAT, eglTextureFormat, EGL_TEXTURE_TARGET,
                eglTextureTarget,   EGL_NONE,         EGL_NONE,
            };

            // Multisampled textures are not supported on D3D9.
            ASSERT(sampleCount <= 1);
            ASSERT(sampleQuality == 0);

            IDirect3DTexture9 *texture = nullptr;
            EXPECT_TRUE(SUCCEEDED(mD3D9Device->CreateTexture(
                static_cast<UINT>(width), static_cast<UINT>(height), 1, D3DUSAGE_RENDERTARGET,
                D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture, nullptr)));

            EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(display, EGL_D3D_TEXTURE_ANGLE,
                                                                  texture, config, attribs);

            texture->Release();

            return pbuffer;
        }
        else
        {
            return EGL_NO_SURFACE;
        }
    }
示例#4
0
EGLSurface
EGLDevice::createPbuffer(int width, int height, EGLClientBuffer buf, EGLenum type)
{
    const EGLint attribs[] = {
        EGL_WIDTH,      width,
        EGL_HEIGHT,     height,
        EGL_NONE
    };

    EGLSurface pbuf = eglCreatePbufferFromClientBuffer(_eglDisplay, type, buf,
                                              _eglConfig, attribs);
    if (pbuf == EGL_NO_SURFACE) {
        log_error( "eglCreatePbufferFromClientBuffer() failed (error 0x%x)",
                   eglGetError());
        return EGL_NO_SURFACE;
    }

    _pbuffers.push_back(pbuf);
    
    return pbuf;
}
void QVGEGLWindowSurfaceVGImage::beginPaint(QWidget *widget)
{
    QEglContext *context = ensureContext(widget);
    if (context) {
        if (recreateBackBuffer || backBufferSurface == EGL_NO_SURFACE) {
            // Create a VGImage object to act as the back buffer
            // for this window.  We have to create the VGImage with a
            // current context, so activate the main surface for the window.
            context->makeCurrent(mainSurface());
            recreateBackBuffer = false;
            if (backBufferSurface != EGL_NO_SURFACE) {
                eglDestroySurface(QEgl::display(), backBufferSurface);
                backBufferSurface = EGL_NO_SURFACE;
            }
            if (backBuffer != VG_INVALID_HANDLE) {
                vgDestroyImage(backBuffer);
            }
            VGImageFormat format = qt_vg_config_to_vg_format(context);
            backBuffer = vgCreateImage
                (format, size.width(), size.height(),
                 VG_IMAGE_QUALITY_FASTER);
            if (backBuffer != VG_INVALID_HANDLE) {
                // Create an EGL surface for rendering into the VGImage.
                backBufferSurface = eglCreatePbufferFromClientBuffer
                    (QEgl::display(), EGL_OPENVG_IMAGE,
                     (EGLClientBuffer)(backBuffer),
                     context->config(), NULL);
                if (backBufferSurface == EGL_NO_SURFACE) {
                    vgDestroyImage(backBuffer);
                    backBuffer = VG_INVALID_HANDLE;
                }
            }
        }
        if (backBufferSurface != EGL_NO_SURFACE)
            context->makeCurrent(backBufferSurface);
        else
            context->makeCurrent(mainSurface());
        isPaintingActive = true;
    }
}
示例#6
0
EGLSurface EGLDisplayOpenVG::createPbufferFromClientBuffer(
    EGLClientBuffer clientBuffer, EGLenum bufferType, const EGLConfig& config, EGLint* errorCode)
{
    EGLSurface surface = eglCreatePbufferFromClientBuffer(m_display,
        bufferType, clientBuffer, config, 0 /* attribList */);

    if (errorCode)
        *errorCode = eglGetError();
    else
        ASSERT_EGL_NO_ERROR();

    if (surface == EGL_NO_SURFACE)
        return EGL_NO_SURFACE;

    EGLint surfaceConfigId;
    EGLBoolean success = eglGetConfigAttrib(m_display, config, EGL_CONFIG_ID, &surfaceConfigId);
    ASSERT(success == EGL_TRUE);
    ASSERT(surfaceConfigId != EGL_BAD_ATTRIBUTE);

    ASSERT(!m_surfaceConfigIds.contains(surface));
    m_surfaceConfigIds.set(surface, surfaceConfigId);
    return surface;
}
/* EGLSurface eglCreatePbufferFromClientBuffer ( EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list ) */
static jobject
android_eglCreatePbufferFromClientBuffer
  (JNIEnv *_env, jobject _this, jobject dpy, jint buftype, jlong buffer, jobject config, jintArray attrib_list_ref, jint offset) {
    jint _exception = 0;
    const char * _exceptionType = NULL;
    const char * _exceptionMessage = NULL;
    EGLSurface _returnValue = (EGLSurface) 0;
    EGLDisplay dpy_native = (EGLDisplay) fromEGLHandle(_env, egldisplayGetHandleID, dpy);
    EGLConfig config_native = (EGLConfig) fromEGLHandle(_env, eglconfigGetHandleID, config);
    bool attrib_list_sentinel = false;
    EGLint *attrib_list_base = (EGLint *) 0;
    jint _remaining;
    EGLint *attrib_list = (EGLint *) 0;

    if (!attrib_list_ref) {
        _exception = 1;
        _exceptionType = "java/lang/IllegalArgumentException";
        _exceptionMessage = "attrib_list == null";
        goto exit;
    }
    if (offset < 0) {
        _exception = 1;
        _exceptionType = "java/lang/IllegalArgumentException";
        _exceptionMessage = "offset < 0";
        goto exit;
    }
    _remaining = _env->GetArrayLength(attrib_list_ref) - offset;
    attrib_list_base = (EGLint *)
        _env->GetPrimitiveArrayCritical(attrib_list_ref, (jboolean *)0);
    attrib_list = attrib_list_base + offset;
    attrib_list_sentinel = false;
    for (int i = _remaining - 1; i >= 0; i--)  {
        if (attrib_list[i] == EGL_NONE){
            attrib_list_sentinel = true;
            break;
        }
    }
    if (attrib_list_sentinel == false) {
        _exception = 1;
        _exceptionType = "java/lang/IllegalArgumentException";
        _exceptionMessage = "attrib_list must contain EGL_NONE!";
        goto exit;
    }

    _returnValue = eglCreatePbufferFromClientBuffer(
        (EGLDisplay)dpy_native,
        (EGLenum)buftype,
        reinterpret_cast<EGLClientBuffer>(buffer),
        (EGLConfig)config_native,
        (EGLint *)attrib_list
    );

exit:
    if (attrib_list_base) {
        _env->ReleasePrimitiveArrayCritical(attrib_list_ref, attrib_list_base,
            JNI_ABORT);
    }
    if (_exception) {
        jniThrowException(_env, _exceptionType, _exceptionMessage);
    }
    return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue);
}
TInt CHuiVg10VgImageBinder::BindClientBuffer(TUint aBuffer)
    {

    // This returns the index of the corresponding aBuffer stored in the array. 
    // If KErrNotFound is returned,it indicates that this is the first BindClientBuffer
    // call for aBuffer and hence eglPbufferfromclient has to be created for this buffer
    TInt bufferIndex = iGroupOpacityImages.Find(aBuffer);
    
    
    // This check mandates that iSavedDraw/Read Surfaces are stored only for the first time
    // (i.e., before any pbufferfromclient surfaces are created).This is because when there are concurrent 
    // BindToImageL calls,we would eventually be losing track of the base window surface on
    // top of which the vgImage has to be drawn. 
    if(iGroupOpacityImages.Count() == 0)							
        {
        // Save current context and surfaces
        iSavedContext = eglGetCurrentContext();
        iSavedDrawSurface = eglGetCurrentSurface(EGL_DRAW);
        iSavedReadSurface = eglGetCurrentSurface(EGL_READ);
        }

    // Buffer Index would be KErrNotFound if this is the first BindClientBuffer call for aBuffer
    // (there would be multiple BindClientBuffer calls for an aBuffer) and hence corresponding
    // pbufferfromclient surface has to be created for that aBuffer.    
    if(bufferIndex == KErrNotFound)
        {
        // Check whether we should use the Alpha format bit
        VGImageFormat imageFormat = (VGImageFormat)vgGetParameteri(aBuffer, VG_IMAGE_FORMAT);
        TInt maskBit = 0;
        if (imageFormat == VG_sRGBA_8888_PRE)
            {
            maskBit = EGL_VG_ALPHA_FORMAT_PRE_BIT;
            }

        const TInt BITS_PER_CHANNEL = 8;
        // Choose an EGL config
        const EGLint attrs[] =
            {
            EGL_RENDERABLE_TYPE,    EGL_OPENVG_BIT,
            EGL_SURFACE_TYPE,       EGL_PBUFFER_BIT | maskBit,
            EGL_RED_SIZE,           BITS_PER_CHANNEL,
            EGL_GREEN_SIZE,         BITS_PER_CHANNEL,
            EGL_BLUE_SIZE,          BITS_PER_CHANNEL,
            EGL_ALPHA_SIZE,         BITS_PER_CHANNEL,
            EGL_NONE
            };

        // Create a context
        TInt configCount = iRenderPlugin->EglChooseConfig(attrs);
        EGLConfig config = iRenderPlugin->EglConfig(0);

        // Create a pbuffer surface
        iEglPBufferSurface_Client = eglCreatePbufferFromClientBuffer(iRenderPlugin->EglDisplay(),
                EGL_OPENVG_IMAGE, 
                static_cast<EGLClientBuffer>(aBuffer),    // Use the param image as buffer
                config, NULL);
        if (iEglPBufferSurface_Client == EGL_NO_SURFACE)
            {
            HUI_DEBUG1(_L("CHuiVg10VgImageBinder::BindClientBuffer() - EGL Surface could not be created, eglErr: %04x"), eglGetError() );
            return KErrGeneral;
            }
        iGroupOpacitySurfaces.Append(iEglPBufferSurface_Client);
        iGroupOpacityImages.Append(aBuffer);
        } 
        // Control would go to else part indicating that this is not the first BindClientBuffer for aBuffer 
        // and hence the corresponding eglPBufferfromClient surface could be retrieved with the bufferIndex
    else				
        {
        iEglPBufferSurface_Client = iGroupOpacitySurfaces[bufferIndex];
        }

    EGLContext context = iRenderPlugin->EglSharedContext();
    
    // eglMakeCurrent with EGL_NO_SURFACE de-couples vgImage from an old eglpbufferfromclient surface.
    // Otherwise in a multiple BindClientBuffer scenario for the same vgImage, eglMakeCurrent
    // fails with an EGL_BAD_ACCESS error (vgimage already inuse error)
    eglMakeCurrent(iRenderPlugin->EglDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, context);      
    
    // Bind our own PBuffer surface (from VGImage)
    if ( eglMakeCurrent(iRenderPlugin->EglDisplay(), iEglPBufferSurface_Client, iEglPBufferSurface_Client, context ) == EGL_FALSE )
        {
        HUI_DEBUG1(_L("CHuiVg10VgImageBinder::BindClientBuffer() - EGL Surface could not be made current, eglErr: %04x"), eglGetError());
        TInt eglError = eglGetError();
        return KErrGeneral;
        }

    // Alles in Ordnung!
    return KErrNone;
    }
示例#9
0
bool EGLInteropResource::ensureD3D9EGL(int w, int h) {
    if (surface9 && res[0].w == w && res[0].h == h)
        return true;
#if QTAV_HAVE(GUI_PRIVATE)
    QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
    egl->dpy = static_cast<EGLDisplay>(nativeInterface->nativeResourceForContext("eglDisplay", QOpenGLContext::currentContext()));
    EGLConfig egl_cfg = static_cast<EGLConfig>(nativeInterface->nativeResourceForContext("eglConfig", QOpenGLContext::currentContext()));
#else
#ifdef Q_OS_WIN
#if QT_VERSION < QT_VERSION_CHECK(5, 5, 0)
#ifdef _MSC_VER
#pragma message("ANGLE version in Qt<5.5 does not support eglQueryContext. You must upgrade your runtime ANGLE libraries")
#else
#warning "ANGLE version in Qt<5.5 does not support eglQueryContext. You must upgrade your runtime ANGLE libraries"
#endif //_MSC_VER
#endif
#endif //Q_OS_WIN
    // eglQueryContext() added (Feb 2015): https://github.com/google/angle/commit/8310797003c44005da4143774293ea69671b0e2a
    egl->dpy = eglGetCurrentDisplay();
    qDebug("EGL version: %s, client api: %s", eglQueryString(egl->dpy, EGL_VERSION), eglQueryString(egl->dpy, EGL_CLIENT_APIS));
    // TODO: check runtime egl>=1.4 for eglGetCurrentContext()
    EGLint cfg_id = 0;
    EGL_ENSURE(eglQueryContext(egl->dpy, eglGetCurrentContext(), EGL_CONFIG_ID , &cfg_id) == EGL_TRUE, false);
    qDebug("egl config id: %d", cfg_id);
    EGLint nb_cfg = 0;
    EGL_ENSURE(eglGetConfigs(egl->dpy, NULL, 0, &nb_cfg) == EGL_TRUE, false);
    qDebug("eglGetConfigs number: %d", nb_cfg);
    QVector<EGLConfig> cfgs(nb_cfg); //check > 0
    EGL_ENSURE(eglGetConfigs(egl->dpy, cfgs.data(), cfgs.size(), &nb_cfg) == EGL_TRUE, false);
    EGLConfig egl_cfg = NULL;
    for (int i = 0; i < nb_cfg; ++i) {
        EGLint id = 0;
        eglGetConfigAttrib(egl->dpy, cfgs[i], EGL_CONFIG_ID, &id);
        if (id == cfg_id) {
            egl_cfg = cfgs[i];
            break;
        }
    }
#endif
    qDebug("egl display:%p config: %p", egl->dpy, egl_cfg);
    // check extensions
    QList<QByteArray> extensions = QByteArray(eglQueryString(egl->dpy, EGL_EXTENSIONS)).split(' ');
    // ANGLE_d3d_share_handle_client_buffer will be used if possible
    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
    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);
    }

    SafeRelease(&surface9);
    SafeRelease(&texture9);
    // _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(device9->CreateTexture(w, h, 1,
                                        D3DUSAGE_RENDERTARGET,
                                        has_alpha ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8,
                                        D3DPOOL_DEFAULT,
                                        &texture9,
                                        &share_handle) , false);
    DX_ENSURE(texture9->GetSurfaceLevel(0, &surface9), 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);
    }
    return true;
}
示例#10
0
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;
}