bool GLInteropResource::ensureResource(int w, int h, GLuint tex) { Q_UNUSED(tex); if (!ensureWGL()) return false; if (dx_surface && width == w && height == h) return true; releaseDX(); HANDLE share_handle = NULL; #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) const bool has_alpha = QOpenGLContext::currentContext()->format().hasAlpha(); #else const bool has_alpha = QOpenGLContext::currentContext()->format().alpha(); #endif // _A8 for a yuv plane 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); // required by d3d9 not d3d10&11: https://www.opengl.org/registry/specs/NV/DX_interop2.txt WGL_WARN(wgl->DXSetResourceShareHandleNV(dx_surface, share_handle)); width = w; height = h; return true; }
/** * It creates a Direct3D device manager */ bool VideoDecoderDXVAPrivate::D3dCreateDeviceManager() { typedef HRESULT (WINAPI *CreateDeviceManager9Func)(UINT *pResetToken, IDirect3DDeviceManager9 **); CreateDeviceManager9Func CreateDeviceManager9 = (CreateDeviceManager9Func)GetProcAddress(hdxva2_dll, "DXVA2CreateDirect3DDeviceManager9"); if (!CreateDeviceManager9) { qWarning("cannot load function DXVA2CreateDirect3DDeviceManager9"); return false; } qDebug("OurDirect3DCreateDeviceManager9 Success!"); DX_ENSURE_OK(CreateDeviceManager9(&token, &devmng), false); qDebug("obtained IDirect3DDeviceManager9"); //http://msdn.microsoft.com/en-us/library/windows/desktop/ms693525%28v=vs.85%29.aspx DX_ENSURE_OK(devmng->ResetDevice(d3ddev, token), false); return true; }
EGLInteropResource::EGLInteropResource(IDirect3DDevice9 * d3device) : InteropResource(d3device) , egl(new EGL()) , dx_query(NULL) { DX_ENSURE_OK(d3device->CreateQuery(D3DQUERYTYPE_EVENT, &dx_query)); dx_query->Issue(D3DISSUE_END); }
bool GLInteropResource::map(IDirect3DSurface9 *surface, GLuint tex, int w, int h, int) { if (!ensureResource(w, h, tex)) { releaseDX(); return false; } // open/close and register/unregster in every map/unmap to ensure called in current context and avoid crash (tested on intel driver) // interop operations begin WGL_ENSURE((interop_dev = wgl->DXOpenDeviceNV(d3ddev)) != NULL, false); // call in ensureResource or in map? WGL_ENSURE((interop_obj = wgl->DXRegisterObjectNV(interop_dev, dx_surface, tex, GL_TEXTURE_2D, WGL_ACCESS_READ_ONLY_NV)) != NULL, false); // prepare dx resources for gl const RECT src = { 0, 0, w, h}; DX_ENSURE_OK(d3ddev->StretchRect(surface, &src, dx_surface, NULL, D3DTEXF_NONE), false); // lock dx resources WGL_ENSURE(wgl->DXLockObjectsNV(interop_dev, 1, &interop_obj), false); WGL_ENSURE(wgl->DXObjectAccessNV(interop_obj, WGL_ACCESS_READ_ONLY_NV), false); DYGL(glBindTexture(GL_TEXTURE_2D, tex)); return true; }
bool VideoDecoderDXVAPrivate::DxCreateVideoDecoder(int codec_id, int w, int h) { if (!vs || !d3ddev) { qWarning("d3d is not ready. IDirectXVideoService: %p, IDirect3DDevice9: %p", vs, d3ddev); return false; } qDebug("DxCreateVideoDecoder id %d %dx%d, surfaces: %u", codec_id, w, h, surface_count); /* Allocates all surfaces needed for the decoder */ surface_width = aligned(w); surface_height = aligned(h); if (surface_auto) { switch (codec_id) { case QTAV_CODEC_ID(HEVC): case QTAV_CODEC_ID(H264): surface_count = 16 + 4; break; case QTAV_CODEC_ID(MPEG1VIDEO): case QTAV_CODEC_ID(MPEG2VIDEO): surface_count = 2 + 4; default: surface_count = 2 + 4; break; } if (codec_ctx->active_thread_type & FF_THREAD_FRAME) surface_count += codec_ctx->thread_count; } qDebug(">>>>>>>>>>>>>>>>>>>>>surfaces: %d, active_thread_type: %d, threads: %d, refs: %d", surface_count, codec_ctx->active_thread_type, codec_ctx->thread_count, codec_ctx->refs); if (surface_count == 0) { qWarning("internal error: wrong surface count. %u auto=%d", surface_count, surface_auto); surface_count = 16 + 4; } IDirect3DSurface9* surface_list[VA_DXVA2_MAX_SURFACE_COUNT]; qDebug("%s @%d vs=%p surface_count=%d surface_width=%d surface_height=%d" , __FUNCTION__, __LINE__, vs, surface_count, surface_width, surface_height); DX_ENSURE_OK(vs->CreateSurface(surface_width, surface_height, surface_count - 1, render, D3DPOOL_DEFAULT, 0, DXVA2_VideoDecoderRenderTarget, surface_list, NULL) , false); memset(surfaces, 0, sizeof(surfaces)); for (unsigned i = 0; i < surface_count; i++) { va_surface_t *surface = &this->surfaces[i]; surface->d3d = surface_list[i]; surface->refcount = 0; surface->order = 0; } qDebug("IDirectXVideoAccelerationService_CreateSurface succeed with %d surfaces (%dx%d)", surface_count, w, h); /* */ DXVA2_VideoDesc dsc; ZeroMemory(&dsc, sizeof(dsc)); dsc.SampleWidth = w; //coded_width dsc.SampleHeight = h; //coded_height dsc.Format = render; dsc.InputSampleFreq.Numerator = 0; dsc.InputSampleFreq.Denominator = 0; dsc.OutputFrameFreq = dsc.InputSampleFreq; dsc.UABProtectionLevel = FALSE; dsc.Reserved = 0; // see xbmc /* FIXME I am unsure we can let unknown everywhere */ DXVA2_ExtendedFormat *ext = &dsc.SampleFormat; ext->SampleFormat = 0;//DXVA2_SampleProgressiveFrame;//xbmc. DXVA2_SampleUnknown; ext->VideoChromaSubsampling = 0;//DXVA2_VideoChromaSubsampling_Unknown; ext->NominalRange = 0;//DXVA2_NominalRange_Unknown; ext->VideoTransferMatrix = 0;//DXVA2_VideoTransferMatrix_Unknown; ext->VideoLighting = 0;//DXVA2_VideoLighting_dim;//xbmc. DXVA2_VideoLighting_Unknown; ext->VideoPrimaries = 0;//DXVA2_VideoPrimaries_Unknown; ext->VideoTransferFunction = 0;//DXVA2_VideoTransFunc_Unknown; /* List all configurations available for the decoder */ UINT cfg_count = 0; DXVA2_ConfigPictureDecode *cfg_list = NULL; DX_ENSURE_OK(vs->GetDecoderConfigurations(input, &dsc, NULL, &cfg_count, &cfg_list) , false); qDebug("we got %d decoder configurations", cfg_count); /* Select the best decoder configuration */ int cfg_score = 0; for (unsigned i = 0; i < cfg_count; i++) { const DXVA2_ConfigPictureDecode *cfg = &cfg_list[i]; qDebug("configuration[%d] ConfigBitstreamRaw %d", i, cfg->ConfigBitstreamRaw); int score; if (cfg->ConfigBitstreamRaw == 1) score = 1; else if (codec_id == QTAV_CODEC_ID(H264) && cfg->ConfigBitstreamRaw == 2) score = 2; else continue; if (IsEqualGUID(cfg->guidConfigBitstreamEncryption, DXVA_NoEncrypt)) score += 16; if (cfg_score < score) { this->cfg = *cfg; cfg_score = score; } } CoTaskMemFree(cfg_list); if (cfg_score <= 0) { qWarning("Failed to find a supported decoder configuration"); return false; } /* Create the decoder */ DX_ENSURE_OK(vs->CreateVideoDecoder(input, &dsc, &cfg, surface_list, surface_count, &decoder), false); qDebug("IDirectXVideoDecoderService_CreateVideoDecoder succeed. decoder=%p", decoder); return true; }
/** * Find the best suited decoder mode GUID and render format. */ bool VideoDecoderDXVAPrivate::DxFindVideoServiceConversion(GUID *input, D3DFORMAT *output) { /* Retreive supported modes from the decoder service */ UINT input_count = 0; GUID *input_list = NULL; DX_ENSURE_OK(vs->GetDecoderDeviceGuids(&input_count, &input_list), false); for (unsigned i = 0; i < input_count; i++) { const GUID &g = input_list[i]; const dxva2_mode_t *mode = Dxva2FindMode(&g); if (mode) { qDebug("- '%s' is supported by hardware", mode->name); } else { qDebug("- Unknown GUID = %08X-%04x-%04x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x", (unsigned)g.Data1, g.Data2, g.Data3 , g.Data4[0], g.Data4[1] , g.Data4[2], g.Data4[3], g.Data4[4], g.Data4[5], g.Data4[6], g.Data4[7]); } } /* Try all supported mode by our priority */ const dxva2_mode_t *mode = dxva2_modes; for (; mode->name; ++mode) { if (!mode->codec || mode->codec != codec_ctx->codec_id) { qDebug("codec does not match to %s: %s", avcodec_get_name(codec_ctx->codec_id), avcodec_get_name((AVCodecID)mode->codec)); continue; } qDebug("DXVA found codec: %s. Check runtime support for the codec.", mode->name); bool is_supported = false; for (const GUID *g = &input_list[0]; !is_supported && g < &input_list[input_count]; g++) { is_supported = IsEqualGUID(*mode->guid, *g); } if (is_supported) { qDebug("Check profile support: %s", AVDecoderPrivate::getProfileName(codec_ctx)); is_supported = !mode->profiles || !mode->profiles[0] || codec_ctx->profile <= 0; if (!is_supported) { for (const int *profile = &mode->profiles[0]; *profile; ++profile) { if (*profile == codec_ctx->profile) { is_supported = true; break; } } } } if (!is_supported) continue; UINT output_count = 0; D3DFORMAT *output_list = NULL; if (FAILED(vs->GetDecoderRenderTargets(*mode->guid, &output_count, &output_list))) { qWarning("IDirectXVideoDecoderService_GetDecoderRenderTargets failed"); continue; } qDebug("supprted output count: %d", output_count); for (const D3DFORMAT *f = output_list; f < &output_list[output_count]; ++f) { const d3d_format_t *format = D3dFindFormat(*f); if (format) { qDebug("%s is supported for output", format->name); } else { qDebug("%d is supported for output (%4.4s)", *f, (const char*)f); } } for (const d3d_format_t *format = d3d_formats; format->name; ++format) { bool is_supported = false; for (unsigned k = 0; !is_supported && k < output_count; k++) { is_supported = format->format == output_list[k]; } if (!is_supported) continue; /* We have our solution */ qDebug("Using '%s' to decode to '%s'", mode->name, format->name); *input = *mode->guid; *output = format->format; CoTaskMemFree(output_list); CoTaskMemFree(input_list); return true; } CoTaskMemFree(output_list); } CoTaskMemFree(input_list); return false; }
bool VideoDecoderDXVAPrivate::DxCreateVideoService() { DX_ENSURE_OK(devmng->OpenDeviceHandle(&device), false); DX_ENSURE_OK(devmng->GetVideoService(device, IID_IDirectXVideoDecoderService, (void**)&vs), false); return true; }
/** * Find the best suited decoder mode GUID and render format. */ bool VideoDecoderDXVAPrivate::DxFindVideoServiceConversion(GUID *input, D3DFORMAT *output) { /* Retreive supported modes from the decoder service */ UINT input_count = 0; GUID *input_list = NULL; DX_ENSURE_OK(vs->GetDecoderDeviceGuids(&input_count, &input_list), false); for (unsigned i = 0; i < input_count; i++) { const GUID &g = input_list[i]; const dxva2_mode_t *mode = Dxva2FindMode(&g); if (mode) { qDebug("- '%s' is supported by hardware", mode->name); } else { qDebug("- Unknown GUID = %08X-%04x-%04x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x", (unsigned)g.Data1, g.Data2, g.Data3 , g->Data4[0], g->Data4[1] , g->Data4[2], g->Data4[3], g->Data4[4], g->Data4[5], g->Data4[6], g->Data4[7]); } } /* Try all supported mode by our priority */ for (unsigned i = 0; dxva2_modes[i].name; i++) { const dxva2_mode_t *mode = &dxva2_modes[i]; if (!mode->codec || mode->codec != codec_ctx->codec_id) { qDebug("codec does not match to %s: %s", avcodec_get_name(codec_ctx->codec_id), avcodec_get_name((AVCodecID)mode->codec)); continue; } if (codec_ctx->profile == FF_PROFILE_HEVC_MAIN_10 && !IsEqualGUID(*mode->guid, DXVA_ModeHEVC_VLD_Main10)) { qDebug("profile (%s) does not match to HEVC 10-bit", mode->name); continue; } qDebug("DXVA found codec: %s. Check support for the codec.", mode->name); bool is_suported = false; for (unsigned count = 0; !is_suported && count < input_count; count++) { const GUID &g = input_list[count]; is_suported = IsEqualGUID(*mode->guid, g); /// } if (!is_suported) continue; UINT output_count = 0; D3DFORMAT *output_list = NULL; if (FAILED(vs->GetDecoderRenderTargets(*mode->guid, &output_count, &output_list))) { qWarning("IDirectXVideoDecoderService_GetDecoderRenderTargets failed"); continue; } qDebug("supprted output count: %d", output_count); for (unsigned j = 0; j < output_count; j++) { const D3DFORMAT f = output_list[j]; const d3d_format_t *format = D3dFindFormat(f); if (format) { qDebug("%s is supported for output", format->name); } else { qDebug("%d is supported for output (%4.4s)", f, (const char*)&f); } } for (unsigned j = 0; d3d_formats[j].name; j++) { const d3d_format_t *format = &d3d_formats[j]; bool is_suported = false; for (unsigned k = 0; !is_suported && k < output_count; k++) { is_suported = format->format == output_list[k]; } if (!is_suported) continue; /* We have our solution */ qDebug("Using '%s' to decode to '%s'", mode->name, format->name); *input = *mode->guid; *output = format->format; CoTaskMemFree(output_list); CoTaskMemFree(input_list); return true; } CoTaskMemFree(output_list); } CoTaskMemFree(input_list); 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; }
bool EGLInteropResource::ensureSurface(int w, int h) { if (dx_surface && width == w && height == 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); } 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; }