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; } }
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; } }
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; }
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; }
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; }