bool EGLInteropResource::map(IDirect3DSurface9* surface, GLuint tex, int w, int h, int H) { D3DSURFACE_DESC dxvaDesc; surface->GetDesc(&dxvaDesc); DYGL(glBindTexture(GL_TEXTURE_2D, tex)); const RECT src = { 0, 0, w, h}; HRESULT ret = device9->StretchRect(surface, &src, surface9, NULL, D3DTEXF_NONE); if (SUCCEEDED(ret)) { if (query9) { // Flush the draw command now. Ideally, this should be done immediately before the draw call that uses the texture. Flush it once here though. query9->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; // skip at decoder.close() while (/*!skip_dx.load() && */(query9->GetData(NULL, 0, D3DGETDATA_FLUSH) == FALSE) && ++k < 10) { Sleep(1); } } eglBindTexImage(egl->dpy, egl->surface, EGL_BACK_BUFFER); } else { qWarning() << "map to egl error: " << ret << " - " << qt_error_string(ret); } DYGL(glBindTexture(GL_TEXTURE_2D, 0)); return true; }
EGLTextureFromPixmap::EGLTextureFromPixmap(const NativePixmap handle, bool hasAlpha, EGLConfig config) : m_eglImage(0) , m_surface(EGL_NO_SURFACE) { if (!handle) return; static bool textureFromPixmapSupported = GLPlatformContext::supportsEGLExtension(EGLHelper::eglDisplay(), "EGL_NOK_texture_from_pixmap"); if (textureFromPixmapSupported) { const EGLint pixmapAttribs[] = { EGL_TEXTURE_FORMAT, hasAlpha ? EGL_TEXTURE_RGBA : EGL_TEXTURE_RGB, EGL_TEXTURE_TARGET, EGL_TEXTURE_2D, EGL_NONE }; m_surface = eglCreatePixmapSurface(EGLHelper::eglDisplay(), config, handle, pixmapAttribs); if (m_surface != EGL_NO_SURFACE && !eglBindTexImage(EGLHelper::eglDisplay(), m_surface, EGL_BACK_BUFFER)) destroy(); } if (m_surface != EGL_NO_SURFACE) return; static const EGLint imageAttrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE }; EGLHelper::createEGLImage(&m_eglImage, EGL_NATIVE_PIXMAP_KHR, (EGLClientBuffer)(handle), imageAttrs); if (m_eglImage) { EGLHelper::imageTargetTexture2DOES(m_eglImage); EGLint error = eglGetError(); if (error != EGL_SUCCESS) destroy(); } }
bool EGLInteropResource::map(IDirect3DSurface9* surface, GLuint tex, int w, int h, int) { if (!ensureSurface(w, h)) { releaseEGL(); releaseDX(); return false; } const RECT src = { 0, 0, (~0-1)&w, (~0-1)&h}; DX_ENSURE(d3ddev->StretchRect(surface, &src, dx_surface, NULL, D3DTEXF_NONE), false); 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); //StretchRect does not supports odd values // 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); } } DYGL(glBindTexture(GL_TEXTURE_2D, tex)); eglBindTexImage(egl->dpy, egl->surface, EGL_BACK_BUFFER); DYGL(glBindTexture(GL_TEXTURE_2D, 0)); return true; }
static enum piglit_result draw(struct egl_state *state) { EGLSurface *pixmap; EGLint inv; float red[] = { 0.4, 0.0, 0.0, 1.0 }; float purple[] = { 0.5, 0.0, 0.5, 1.0 }; enum piglit_result result = PIGLIT_PASS; if (!eglGetConfigAttrib(state->egl_dpy, state->cfg, EGL_Y_INVERTED_NOK, &inv)) { fprintf(stderr, "eglGetConfigAttrib(EGL_Y_INVERTED_NOK) failed\n"); return PIGLIT_FAIL; } printf("EGL_Y_INVERTED_NOK: %s\n", inv ? "TRUE" : "FALSE"); pixmap = egl_util_create_pixmap(state, 100, 100, pixmap_attribs); if (!eglMakeCurrent(state->egl_dpy, pixmap, pixmap, state->ctx)) { fprintf(stderr, "eglMakeCurrent() failed\n"); piglit_report_result(PIGLIT_FAIL); } /* Clear pixmap to purple */ glClearColor(0.5, 0.0, 0.5, 1.0); glClear(GL_COLOR_BUFFER_BIT); if (!eglMakeCurrent(state->egl_dpy, state->surf, state->surf, state->ctx)) { fprintf(stderr, "eglMakeCurrent() failed\n"); piglit_report_result(PIGLIT_FAIL); } glViewport(0, 0, state->width, state->height); piglit_ortho_projection(state->width, state->height, GL_FALSE); glClearColor(0.4, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); glEnable(GL_TEXTURE_2D); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); eglBindTexImage(state->egl_dpy, pixmap, EGL_BACK_BUFFER); piglit_draw_rect_tex(20, 20, 100, 100, 0, 0, 1, 1); if (!piglit_probe_pixel_rgba(10, 10, red) || !piglit_probe_pixel_rgba(50, 10, red) || !piglit_probe_pixel_rgba(10, 50, red) || !piglit_probe_pixel_rgba(50, 50, purple) || !piglit_probe_pixel_rgba(110, 110, purple) || !piglit_probe_pixel_rgba(130, 130, red)) result = PIGLIT_FAIL; eglSwapBuffers(state->egl_dpy, state->surf); return result; }
bool QGLPixelBuffer::bindToDynamicTexture(GLuint texture_id) { #if QGL_RENDER_TEXTURE Q_D(QGLPixelBuffer); if (d->invalid || d->textureFormat == EGL_NONE || !d->ctx) return false; glBindTexture(GL_TEXTURE_2D, texture_id); return eglBindTexImage(d->ctx->display(), d->ctx->surface(), EGL_BACK_BUFFER); #else Q_UNUSED(texture_id); return false; #endif }
bool EGLTextureFromPixmap::bindTexImage() { if (m_surface != EGL_NO_SURFACE) { bool success = eglBindTexImage(EGLHelper::eglDisplay(), m_surface, EGL_BACK_BUFFER); return success; } if (m_eglImage) { EGLHelper::imageTargetTexture2DOES(m_eglImage); return true; } return false; }
/* EGLBoolean eglBindTexImage ( EGLDisplay dpy, EGLSurface surface, EGLint buffer ) */ static jboolean android_eglBindTexImage (JNIEnv *_env, jobject _this, jobject dpy, jobject surface, jint buffer) { EGLBoolean _returnValue = (EGLBoolean) 0; EGLDisplay dpy_native = (EGLDisplay) fromEGLHandle(_env, egldisplayGetHandleID, dpy); EGLSurface surface_native = (EGLSurface) fromEGLHandle(_env, eglsurfaceGetHandleID, surface); _returnValue = eglBindTexImage( (EGLDisplay)dpy_native, (EGLSurface)surface_native, (EGLint)buffer ); return (jboolean)_returnValue; }
/* private native int _eglBindTexImage ( int display , int surface , int buffer ) ; */ KNIEXPORT KNI_RETURNTYPE_INT Java_javax_microedition_khronos_egl_EGL10Impl__1eglBindTexImage() { jint display = KNI_GetParameterAsInt(1); jint surface = KNI_GetParameterAsInt(2); jint buffer = KNI_GetParameterAsInt(3); jint returnValue = (jint)eglBindTexImage((EGLDisplay)display, (EGLSurface)surface, (EGLint)buffer); #ifdef DEBUG printf("eglBindTexImage(0x%x, 0x%x, %d) = %d\n", display, surface, buffer, returnValue); #endif KNI_ReturnInt(returnValue); }
static void draw(void) { use_pbuffer(); draw_triangle(); use_window(); eglBindTexImage(dpy, surf_pbuf, EGL_BACK_BUFFER); glPushMatrix(); glRotatef(view_rotx, 1, 0, 0); glRotatef(view_roty, 0, 1, 0); glRotatef(view_rotz, 0, 0, 1); draw_textured_cube(); glPopMatrix(); eglReleaseTexImage(dpy, surf_pbuf, EGL_BACK_BUFFER); }
static void texture_gears(struct egl_manager *eman, int surface_type) { static const GLint verts[12] = { -5, -6, -10, 5, -6, -10, -5, 4, 10, 5, 4, 10 }; static const GLint tex_coords[8] = { 0, 0, 1, 0, 0, 1, 1, 1 }; eglMakeCurrent(eman->dpy, eman->win, eman->win, eman->ctx); glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_TEXTURE_2D); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glVertexPointer(3, GL_INT, 0, verts); glTexCoordPointer(2, GL_INT, 0, tex_coords); if (surface_type == GEARS_PBUFFER_TEXTURE) eglBindTexImage(eman->dpy, eman->pbuf, EGL_BACK_BUFFER); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glDisable(GL_TEXTURE_2D); if (surface_type == GEARS_PBUFFER_TEXTURE) eglReleaseTexImage(eman->dpy, eman->pbuf, EGL_BACK_BUFFER); eglSwapBuffers(eman->dpy, eman->win); }
void XCompositeEglClientBufferIntegration::bindTextureToBuffer(struct ::wl_resource *buffer) { XCompositeBuffer *compositorBuffer = XCompositeBuffer::fromResource(buffer); Pixmap pixmap = XCompositeNameWindowPixmap(mDisplay, compositorBuffer->window()); QVector<EGLint> eglConfigSpec = eglbuildSpec(); EGLint matching = 0; EGLConfig config; bool matched = eglChooseConfig(mEglDisplay,eglConfigSpec.constData(),&config,1,&matching); if (!matched || !matching) { qWarning("Could not retrieve a suitable EGL config"); return; } QVector<EGLint> attribList; attribList.append(EGL_TEXTURE_FORMAT); attribList.append(EGL_TEXTURE_RGBA); attribList.append(EGL_TEXTURE_TARGET); attribList.append(EGL_TEXTURE_2D); attribList.append(EGL_NONE); EGLSurface surface = eglCreatePixmapSurface(mEglDisplay,config,pixmap,attribList.constData()); if (surface == EGL_NO_SURFACE) { qDebug() << "Failed to create eglsurface" << pixmap << compositorBuffer->window(); } compositorBuffer->setInvertedY(true); if (!eglBindTexImage(mEglDisplay,surface,EGL_BACK_BUFFER)) { qDebug() << "Failed to bind"; } // eglDestroySurface(mEglDisplay,surface); }
// Test creating a pbuffer from a d3d surface and binding it to a texture TEST_P(D3DTextureTest, BindTexImage) { if (!valid()) { return; } EGLWindow *window = getEGLWindow(); EGLDisplay display = window->getDisplay(); const size_t bufferSize = 32; EGLSurface pbuffer = createPBuffer(bufferSize, bufferSize, EGL_TEXTURE_RGBA, EGL_TEXTURE_2D, 1, 0); ASSERT_EGL_SUCCESS(); ASSERT_NE(pbuffer, EGL_NO_SURFACE); // Apply the Pbuffer and clear it to purple eglMakeCurrent(display, pbuffer, pbuffer, window->getContext()); ASSERT_EGL_SUCCESS(); glViewport(0, 0, static_cast<GLsizei>(bufferSize), static_cast<GLsizei>(bufferSize)); glClearColor(1.0f, 0.0f, 1.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); ASSERT_GL_NO_ERROR(); EXPECT_PIXEL_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2, 255, 0, 255, 255); // Apply the window surface eglMakeCurrent(display, window->getSurface(), window->getSurface(), window->getContext()); // Create a texture and bind the Pbuffer to it GLuint texture = 0; glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); EXPECT_GL_NO_ERROR(); eglBindTexImage(display, pbuffer, EGL_BACK_BUFFER); glViewport(0, 0, getWindowWidth(), getWindowHeight()); ASSERT_EGL_SUCCESS(); // Draw a quad and verify that it is purple glUseProgram(mTextureProgram); glUniform1i(mTextureUniformLocation, 0); drawQuad(mTextureProgram, "position", 0.5f); EXPECT_GL_NO_ERROR(); // Unbind the texture eglReleaseTexImage(display, pbuffer, EGL_BACK_BUFFER); ASSERT_EGL_SUCCESS(); // Verify that purple was drawn EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 0, 255, 255); glDeleteTextures(1, &texture); // Make current with fixture EGL to ensure the Surface can be released immediately. getEGLWindow()->makeCurrent(); eglDestroySurface(display, pbuffer); }
QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmap *pixmap, const qint64 key, QGLContext::BindOptions options) { Q_Q(QGLContext); // The EGL texture_from_pixmap has no facility to invert the y coordinate if (!(options & QGLContext::CanFlipNativePixmapBindOption)) return 0; static bool checkedForTFP = false; static bool haveTFP = false; static bool checkedForEglImageTFP = false; static bool haveEglImageTFP = false; if (!checkedForEglImageTFP) { checkedForEglImageTFP = true; // We need to be able to create an EGLImage from a native pixmap, which was split // into a separate EGL extension, EGL_KHR_image_pixmap. It is possible to have // eglCreateImageKHR & eglDestroyImageKHR without support for pixmaps, so we must // check we have the EGLImage from pixmap functionality. if (QEgl::hasExtension("EGL_KHR_image") || QEgl::hasExtension("EGL_KHR_image_pixmap")) { // Being able to create an EGLImage from a native pixmap is also pretty useless // without the ability to bind that EGLImage as a texture, which is provided by // the GL_OES_EGL_image extension, which we try to resolve here: haveEglImageTFP = qt_resolve_eglimage_gl_extensions(q); if (haveEglImageTFP) qDebug("Found EGL_KHR_image_pixmap & GL_OES_EGL_image extensions (preferred method)!"); } } if (!checkedForTFP) { // Check for texture_from_pixmap egl extension checkedForTFP = true; if (QEgl::hasExtension("EGL_NOKIA_texture_from_pixmap") || QEgl::hasExtension("EGL_EXT_texture_from_pixmap")) { qDebug("Found texture_from_pixmap EGL extension!"); haveTFP = true; } } if (!haveTFP && !haveEglImageTFP) return 0; QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pixmap->data_ptr().data()); Q_ASSERT(pixmapData->classId() == QPixmapData::X11Class); bool hasAlpha = pixmapData->hasAlphaChannel(); bool pixmapHasValidSurface = false; bool textureIsBound = false; GLuint textureId; glGenTextures(1, &textureId); glBindTexture(GL_TEXTURE_2D, textureId); if (haveTFP && pixmapData->gl_surface && hasAlpha == (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha)) { pixmapHasValidSurface = true; } // If we already have a valid EGL surface for the pixmap, we should use it if (pixmapHasValidSurface) { EGLBoolean success; success = eglBindTexImage(QEgl::display(), (EGLSurface)pixmapData->gl_surface, EGL_BACK_BUFFER); if (success == EGL_FALSE) { qWarning() << "eglBindTexImage() failed:" << QEgl::errorString(); eglDestroySurface(QEgl::display(), (EGLSurface)pixmapData->gl_surface); pixmapData->gl_surface = (void*)EGL_NO_SURFACE; } else textureIsBound = true; } // If the pixmap doesn't already have a valid surface, try binding it via EGLImage // first, as going through EGLImage should be faster and better supported: if (!textureIsBound && haveEglImageTFP) { EGLImageKHR eglImage; EGLint attribs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE }; eglImage = QEgl::eglCreateImageKHR(QEgl::display(), EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, (EGLClientBuffer)QEgl::nativePixmap(pixmap), attribs); QGLContext* ctx = q; glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, eglImage); GLint err = glGetError(); if (err == GL_NO_ERROR) textureIsBound = true; // Once the egl image is bound, the texture becomes a new sibling image and we can safely // destroy the EGLImage we created for the pixmap: if (eglImage != EGL_NO_IMAGE_KHR) QEgl::eglDestroyImageKHR(QEgl::display(), eglImage); } if (!textureIsBound && haveTFP) { // Check to see if the surface is still valid if (pixmapData->gl_surface && hasAlpha != (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha)) { // Surface is invalid! destroyGlSurfaceForPixmap(pixmapData); } if (pixmapData->gl_surface == 0) { EGLConfig config = QEgl::defaultConfig(QInternal::Pixmap, QEgl::OpenGL, hasAlpha ? QEgl::Translucent : QEgl::NoOptions); pixmapData->gl_surface = (void*)QEgl::createSurface(pixmap, config); if (pixmapData->gl_surface == (void*)EGL_NO_SURFACE) return false; } EGLBoolean success; success = eglBindTexImage(QEgl::display(), (EGLSurface)pixmapData->gl_surface, EGL_BACK_BUFFER); if (success == EGL_FALSE) { qWarning() << "eglBindTexImage() failed:" << QEgl::errorString(); eglDestroySurface(QEgl::display(), (EGLSurface)pixmapData->gl_surface); pixmapData->gl_surface = (void*)EGL_NO_SURFACE; haveTFP = false; // If TFP isn't working, disable it's use } else textureIsBound = true; } QGLTexture *texture = 0; if (textureIsBound) { texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, options); pixmapData->flags |= QX11PixmapData::InvertedWhenBoundToTexture; // We assume the cost of bound pixmaps is zero QGLTextureCache::instance()->insert(q, key, texture, 0); glBindTexture(GL_TEXTURE_2D, textureId); } else glDeleteTextures(1, &textureId); return texture; }