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; }
void OpenGLVideo::render(const QRectF &target, const QRectF& roi, const QMatrix4x4& transform) { DPTR_D(OpenGLVideo); Q_ASSERT(d.manager); Q_EMIT beforeRendering(); DYGL(glViewport(d.rect.x(), d.rect.y(), d.rect.width(), d.rect.height())); // viewport was used in gpu filters is wrong, qt quick fbo item's is right(so must ensure setProjectionMatrixToRect was called correctly) const qint64 mt = d.material->type(); if (d.material_type != mt) { qDebug() << "material changed: " << VideoMaterial::typeName(d.material_type) << " => " << VideoMaterial::typeName(mt); d.material_type = mt; } VideoShader *shader = d.user_shader; if (!shader) shader = d.manager->prepareMaterial(d.material, mt); //TODO: print shader type name if changed. prepareMaterial(,sample_code, pp_code) shader->update(d.material); d.material->setDirty(false); // shader->program()->setUniformValue(shader->matrixLocation(), transform*d.matrix); d.gr.setShaderProgram(shader->program()); // uniform end. attribute begin d.bindAttributes(shader, target, roi); // normalize? const bool blending = d.material->hasAlpha(); if (blending) { DYGL(glEnable(GL_BLEND)); DYGL(glBlendFunc(GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA)); } d.gr.render(&d.geometry); if (blending) DYGL(glDisable(GL_BLEND)); // d.shader->program()->release(); //glUseProgram(0) d.unbindAttributes(shader); d.material->unbind(); Q_EMIT afterRendering(); }
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; }
void OpenGLVideo::render(const QRectF &target, const QRectF& roi, const QMatrix4x4& transform) { DPTR_D(OpenGLVideo); Q_ASSERT(d.manager); const qint64 mt = d.material->type(); if (d.material_type != mt) { qDebug() << "material changed: " << VideoMaterial::typeName(d.material_type) << " => " << VideoMaterial::typeName(mt); d.material_type = mt; } VideoShader *shader = d.manager->prepareMaterial(d.material); //TODO: print shader type name if changed. prepareMaterial(,sample_code, pp_code) shader->update(d.material); shader->program()->setUniformValue(shader->opacityLocation(), (GLfloat)1.0); shader->program()->setUniformValue(shader->matrixLocation(), transform*d.matrix); // uniform end. attribute begin d.bindAttributes(shader, target, roi); // normalize? const bool blending = d.material->hasAlpha(); if (blending) { DYGL(glEnable(GL_BLEND)); DYGL(glBlendFunc(GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA)); } DYGL(glDrawArrays(d.geometry.mode(), 0, d.geometry.textureVertexCount())); if (blending) DYGL(glDisable(GL_BLEND)); // d.shader->program()->release(); //glUseProgram(0) d.unbindAttributes(shader); d.material->unbind(); }
void GeometryRenderer::render() { if (!g) return; if (g->indexCount() > 0) { DYGL(glDrawElements(g->primitive(), g->indexCount(), g->indexType(), g->indexData())); } else { DYGL(glDrawArrays(g->primitive(), 0, g->vertexCount())); } }
// TODO: set surface/device size here (viewport?) void OpenGLVideo::setOpenGLContext(QOpenGLContext *ctx) { DPTR_D(OpenGLVideo); if (d.ctx == ctx) return; d.resetGL(); //TODO: is it ok to destroygl resources in another context? d.ctx = ctx; // Qt4: set to null in resetGL() if (!ctx) { return; } if (d.material) delete d.material; d.material = new VideoMaterial(); #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) d.manager = ctx->findChild<ShaderManager*>(QStringLiteral("__qtav_shader_manager")); QSizeF surfaceSize = QOpenGLContext::currentContext()->surface()->size(); #else QSizeF surfaceSize = QSizeF(ctx->device()->width(), ctx->device()->height()); #endif setProjectionMatrixToRect(QRectF(QPointF(), surfaceSize)); if (d.manager) return; // TODO: what if ctx is delete? d.manager = new ShaderManager(ctx); d.manager->setObjectName(QStringLiteral("__qtav_shader_manager")); #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) QObject::connect(ctx, SIGNAL(aboutToBeDestroyed()), this, SLOT(resetGL()), Qt::DirectConnection); //direct? #endif /// get gl info here because context is current(qt ensure it) //const QByteArray extensions(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS))); bool hasGLSL = QOpenGLShaderProgram::hasOpenGLShaderPrograms(); qDebug("OpenGL version: %d.%d hasGLSL: %d", ctx->format().majorVersion(), ctx->format().minorVersion(), hasGLSL); static bool sInfo = true; if (sInfo) { sInfo = false; qDebug("GL_VERSION: %s", DYGL(glGetString(GL_VERSION))); qDebug("GL_VENDOR: %s", DYGL(glGetString(GL_VENDOR))); qDebug("GL_RENDERER: %s", DYGL(glGetString(GL_RENDERER))); qDebug("GL_SHADING_LANGUAGE_VERSION: %s", DYGL(glGetString(GL_SHADING_LANGUAGE_VERSION))); /// check here with current context can ensure the right result. If the first check is in VideoShader/VideoMaterial/decoder or somewhere else, the context can be null bool v = OpenGLHelper::isOpenGLES(); qDebug("Is OpenGLES: %d", v); v = OpenGLHelper::isEGL(); qDebug("Is EGL: %d", v); const int glsl_ver = OpenGLHelper::GLSLVersion(); qDebug("GLSL version: %d", glsl_ver); v = OpenGLHelper::isPBOSupported(); qDebug("Has PBO: %d", v); v = OpenGLHelper::has16BitTexture(); qDebug("Has 16bit texture: %d", v); v = OpenGLHelper::hasRG(); qDebug("Has RG texture: %d", v); qDebug() << ctx->format(); } }
void GeometryRenderer::render() { if (!g) return; bindBuffers(); if (g->indexCount() > 0) { DYGL(glDrawElements(g->primitive(), g->indexCount(), g->indexType(), ibo.isCreated() ? NULL : g->indexData())); // null: data in vao or ibo. not null: data in memory } else { DYGL(glDrawArrays(g->primitive(), 0, g->vertexCount())); } unbindBuffers(); }
int GLSLVersion() { static int v = -1; if (v >= 0) return v; if (!QOpenGLContext::currentContext()) { qWarning("%s: current context is null", __FUNCTION__); return 0; } const char* vs = (const char*)DYGL(glGetString(GL_SHADING_LANGUAGE_VERSION)); int major = 0, minor = 0; // es: "OpenGL ES GLSL ES 1.00 (ANGLE 2.1.99...)" can use ""%*[ a-zA-Z] %d.%d" in sscanf, desktop: "2.1" //QRegExp rx("(\\d+)\\.(\\d+)"); if (strncmp(vs, "OpenGL ES GLSL ES ", 18) == 0) vs += 18; if (sscanf(vs, "%d.%d", &major, &minor) == 2) { v = major * 100 + minor; } else { qWarning("Failed to detect glsl version using GL_SHADING_LANGUAGE_VERSION!"); v = 110; if (isOpenGLES()) v = QOpenGLContext::currentContext()->format().majorVersion() >= 3 ? 300 : 100; } return v; }
void GeometryRenderer::render(Geometry *g) { if (g->indexCount() > 0) { // IBO } else { DYGL(glDrawArrays(g->primitiveType(), 0, g->vertexCount())); } }
void OpenGLRendererBase::onInitializeGL() { DPTR_D(OpenGLRendererBase); //makeCurrent(); #if QT_VERSION >= QT_VERSION_CHECK(4, 8, 0) initializeOpenGLFunctions(); #endif QOpenGLContext *ctx = const_cast<QOpenGLContext*>(QOpenGLContext::currentContext()); //qt4 returns const d.glv.setOpenGLContext(ctx); //const QByteArray extensions(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS))); bool hasGLSL = QOpenGLShaderProgram::hasOpenGLShaderPrograms(); qDebug("OpenGL version: %d.%d hasGLSL: %d", ctx->format().majorVersion(), ctx->format().minorVersion(), hasGLSL); static bool sInfo = true; if (sInfo) { sInfo = false; qDebug("GL_VERSION: %s", DYGL(glGetString(GL_VERSION))); qDebug("GL_VENDOR: %s", DYGL(glGetString(GL_VENDOR))); qDebug("GL_RENDERER: %s", DYGL(glGetString(GL_RENDERER))); qDebug("GL_SHADING_LANGUAGE_VERSION: %s", DYGL(glGetString(GL_SHADING_LANGUAGE_VERSION))); } }
void OpenGLVideo::setProjectionMatrixToRect(const QRectF &v) { DPTR_D(OpenGLVideo); d.rect = v; d.matrix.setToIdentity(); d.matrix.ortho(v); // Mirrored relative to the usual Qt coordinate system with origin in the top left corner. //mirrored = mat(0, 0) * mat(1, 1) - mat(0, 1) * mat(1, 0) > 0; d.update_geo = true; // even true for target_rect != d.rect if (d.ctx && d.ctx == QOpenGLContext::currentContext()) { DYGL(glViewport(d.rect.x(), d.rect.y(), d.rect.width(), d.rect.height())); } }
void OpenGLVideo::render(const QRectF &target, const QRectF& roi, const QMatrix4x4& transform) { DPTR_D(OpenGLVideo); Q_ASSERT(d.manager); VideoShader *shader = d.manager->prepareMaterial(d.material); shader->update(d.material); shader->program()->setUniformValue(shader->opacityLocation(), (GLfloat)1.0); shader->program()->setUniformValue(shader->matrixLocation(), transform*d.matrix); // uniform end. attribute begin d.bindAttributes(shader, target, roi); // normalize? const bool blending = d.material->hasAlpha(); if (blending) { DYGL(glEnable(GL_BLEND)); DYGL(glBlendFunc(GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA)); } DYGL(glDrawArrays(d.geometry.mode(), 0, d.geometry.textureVertexCount())); if (blending) DYGL(glDisable(GL_BLEND)); // d.shader->program()->release(); //glUseProgram(0) d.unbindAttributes(shader); d.material->unbind(); }
bool GLInteropResource::unmap(GLuint tex) { Q_UNUSED(tex); if (!interop_obj || !interop_dev) return false; DYGL(glBindTexture(GL_TEXTURE_2D, 0)); WGL_ENSURE(wgl->DXUnlockObjectsNV(interop_dev, 1, &interop_obj), false); WGL_WARN(wgl->DXUnregisterObjectNV(interop_dev, interop_obj)); // interop operations end WGL_WARN(wgl->DXCloseDeviceNV(interop_dev)); interop_obj = NULL; interop_dev = NULL; return true; }
bool test_gl_param(const gl_param_t& gp, bool* has_16 = 0) { if (!QOpenGLContext::currentContext()) { qWarning("%s: current context is null", __FUNCTION__); return false; } GLuint tex; DYGL(glGenTextures(1, &tex)); DYGL(glBindTexture(GL_TEXTURE_2D, tex)); DYGL(glTexImage2D(GL_TEXTURE_2D, 0, gp.internal_format, 64, 64, 0, gp.format, gp.type, NULL)); GLint param = 0; //GL_PROXY_TEXTURE_2D and no glGenTextures? #ifndef GL_TEXTURE_INTERNAL_FORMAT //only in desktop #define GL_TEXTURE_INTERNAL_FORMAT 0x1003 #endif OpenGLHelper::glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, ¶m); // TODO: check glGetError()? if (param != gp.internal_format) { qDebug("Do not support texture internal format: %#x", gp.internal_format); DYGL(glDeleteTextures(1, &tex)); return false; } if (!has_16) { DYGL(glDeleteTextures(1, &tex)); return true; } *has_16 = false; GLenum pname = 0; #ifndef GL_TEXTURE_RED_SIZE #define GL_TEXTURE_RED_SIZE 0x805C #endif #ifndef GL_TEXTURE_LUMINANCE_SIZE #define GL_TEXTURE_LUMINANCE_SIZE 0x8060 #endif switch (gp.format) { case GL_RED: pname = GL_TEXTURE_RED_SIZE; break; case GL_LUMINANCE: pname = GL_TEXTURE_LUMINANCE_SIZE; break; } param = 0; if (pname) OpenGLHelper::glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, pname, ¶m); if (param) { qDebug("16 bit texture depth: %d.\n", (int)param); *has_16 = (int)param == 16; } DYGL(glDeleteTextures(1, &tex)); return true; }
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; }
void OpenGLVideo::fill(const QColor &color) { DYGL(glClearColor(color.red(), color.green(), color.blue(), color.alpha())); DYGL(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); }