QByteArray compatibleShaderHeader(QOpenGLShader::ShaderType type) { #if BUG_GLES3_ANDROID if (isOpenGLES()) return commonShaderHeader(type); #endif //BUG_GLES3_ANDROID QByteArray h; // #version directive must occur in a compilation unit before anything else, except for comments and white spaces. Default is 100 if not set h.append("#version ").append(QByteArray::number(GLSLVersion())); if (isOpenGLES() && QOpenGLContext::currentContext()->format().majorVersion() > 2) h += " es"; h += "\n"; h += commonShaderHeader(type); if (GLSLVersion() >= 130) { // gl(es) 3 if (type == QOpenGLShader::Vertex) { h += "#define attribute in\n" "#define varying out\n" ; } else if (type == QOpenGLShader::Fragment) { h += "#define varying in\n" "#define gl_FragColor out_color\n" //can not starts with 'gl_' "out vec4 gl_FragColor;\n" ; } } return h; }
bool hasRG() { static int has_rg = -1; if (has_rg >= 0) return !!has_rg; qDebug("check desktop rg: %#X", gl_param_desktop[1].internal_format); if (test_gl_param(gl_param_desktop[1])) { has_rg = 1; return true; } qDebug("check es3 rg: %#X", gl_param_es3[1].internal_format); if (test_gl_param(gl_param_es3[1])) { has_rg = 1; return true; } qDebug("check GL_EXT_texture_rg"); static const char* ext[] = { "GL_EXT_texture_rg", 0}; //RED, RG, R8, RG8 if (hasExtension(ext)) { qDebug("has extension GL_EXT_texture_rg"); has_rg = 1; return true; } qDebug("check gl es>=3 rg"); if (QOpenGLContext::currentContext()) has_rg = isOpenGLES() && QOpenGLContext::currentContext()->format().majorVersion() > 2; return has_rg; }
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 GraphicsContext3DPrivate::createOffscreenBuffers() { glGenFramebuffers(/* count */ 1, &m_context->m_fbo); glGenTextures(1, &m_context->m_texture); glBindTexture(GL_TEXTURE_2D, m_context->m_texture); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glBindTexture(GL_TEXTURE_2D, 0); // Create a multisample FBO. if (m_context->m_attrs.antialias) { glGenFramebuffers(1, &m_context->m_multisampleFBO); glBindFramebuffer(GL_FRAMEBUFFER, m_context->m_multisampleFBO); m_context->m_state.boundFBO = m_context->m_multisampleFBO; glGenRenderbuffers(1, &m_context->m_multisampleColorBuffer); if (m_context->m_attrs.stencil || m_context->m_attrs.depth) glGenRenderbuffers(1, &m_context->m_multisampleDepthStencilBuffer); } else { // Bind canvas FBO. glBindFramebuffer(GL_FRAMEBUFFER, m_context->m_fbo); m_context->m_state.boundFBO = m_context->m_fbo; if (isOpenGLES()) { if (m_context->m_attrs.depth) glGenRenderbuffers(1, &m_context->m_depthBuffer); if (m_context->m_attrs.stencil) glGenRenderbuffers(1, &m_context->m_stencilBuffer); } if (m_context->m_attrs.stencil || m_context->m_attrs.depth) glGenRenderbuffers(1, &m_context->m_depthStencilBuffer); } }
static QSurfaceFormat formatFromConfig(EGLDisplay dpy, EGLConfig config) { QSurfaceFormat format; EGLint value = 0; #define HELPER(__egl__, __qt__) \ eglGetConfigAttrib(dpy, config, EGL_##__egl__, &value); \ format.set##__qt__(value); \ value = 0; #define BUFFER_HELPER(__eglColor__, __color__) \ HELPER(__eglColor__##_SIZE, __color__##BufferSize) BUFFER_HELPER(RED, Red) BUFFER_HELPER(GREEN, Green) BUFFER_HELPER(BLUE, Blue) BUFFER_HELPER(ALPHA, Alpha) BUFFER_HELPER(STENCIL, Stencil) BUFFER_HELPER(DEPTH, Depth) #undef BUFFER_HELPER HELPER(SAMPLES, Samples) #undef HELPER format.setRenderableType(isOpenGLES() ? QSurfaceFormat::OpenGLES : QSurfaceFormat::OpenGL); format.setStereo(false); return format; }
static EGLConfig configFromGLFormat(EGLDisplay dpy, const QSurfaceFormat &format) { #define SIZE( __buffer__ ) format.__buffer__##BufferSize() > 0 ? format.__buffer__##BufferSize() : 0 // not setting samples as QtQuick doesn't need it const EGLint config_attribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RED_SIZE, SIZE(red), EGL_GREEN_SIZE, SIZE(green), EGL_BLUE_SIZE, SIZE(blue), EGL_ALPHA_SIZE, SIZE(alpha), EGL_DEPTH_SIZE, SIZE(depth), EGL_STENCIL_SIZE, SIZE(stencil), EGL_RENDERABLE_TYPE, isOpenGLES() ? EGL_OPENGL_ES2_BIT : EGL_OPENGL_BIT, EGL_NONE, }; #undef SIZE EGLint count; EGLConfig configs[1024]; if (eglChooseConfig(dpy, config_attribs, configs, 1, &count) == EGL_FALSE) { return 0; } if (count != 1) { return 0; } return configs[0]; }
bool AbstractPlatformContext::bindApi() { if (eglBindAPI(isOpenGLES() ? EGL_OPENGL_ES_API : EGL_OPENGL_API) == EGL_FALSE) { return false; } return true; }
void GraphicsContext3DPrivate::blitMultisampleFramebuffer() { if (!m_context->m_attrs.antialias) return; if (!isOpenGLES()) { glBindFramebuffer(GL_READ_FRAMEBUFFER, m_context->m_multisampleFBO); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_context->m_fbo); glBlitFramebuffer(0, 0, m_context->m_currentWidth, m_context->m_currentHeight, 0, 0, m_context->m_currentWidth, m_context->m_currentHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR); } glBindFramebuffer(GL_FRAMEBUFFER, m_context->m_state.boundFBO); }
static const gl_param_t* get_gl_param() { if (!QOpenGLContext::currentContext()) { qWarning("%s: current context is null", __FUNCTION__); return gl_param_compat; } static gl_param_t* gp = 0; if (gp) return gp; bool has_16 = false; // [4] is always available if (test_gl_param(gl_param_desktop[4], &has_16)) { if (has_16 && depth16BitTexture() == 16) gp = (gl_param_t*)gl_param_desktop; else gp = (gl_param_t*)gl_param_desktop_fallback; has_16_tex = has_16; if (!useDeprecatedFormats()) { qDebug("using gl_param_desktop%s", gp == gl_param_desktop? "" : "_fallback"); return gp; } } else if (test_gl_param(gl_param_es3[4], &has_16)) { //3.0 will fail because no glGetTexLevelParameteriv gp = (gl_param_t*)gl_param_es3; has_16_tex = has_16; if (!useDeprecatedFormats()) { qDebug("using gl_param_es3"); return gp; } } else if (isOpenGLES()) { if (QOpenGLContext::currentContext()->format().majorVersion() > 2) gp = (gl_param_t*)gl_param_es3; //for 3.0 else if (hasRG()) gp = (gl_param_t*)gl_param_es2rg; has_16_tex = has_16; if (gp && !useDeprecatedFormats()) { qDebug("using gl_param_%s", gp == gl_param_es3 ? "es3" : "es2rg"); return gp; } } qDebug("fallback to gl_param_compat"); gp = (gl_param_t*)gl_param_compat; has_16_tex = false; return gp; }
bool isEGL() { static int is_egl = -1; if (is_egl >= 0) return !!is_egl; #ifdef Q_OS_IOS is_egl = 0; return false; #endif if (isOpenGLES()) { //TODO: ios has no egl is_egl = 1; return true; } // angle has no QTAV_HAVE(QT_EGL). TODO: no assert in capi, or check egl loaded #if QTAV_HAVE(EGL_CAPI) //&& QTAV_HAVE(QT_EGL) //make sure no crash if no egl library if (!egl::api().loaded()) { //load twice, here and ns func call is_egl = 0; return false; } if (eglGetCurrentDisplay() != EGL_NO_DISPLAY) { //egl can be loaded but glx is used is_egl = 1; return true; } #endif #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) if (QGuiApplication::platformName().contains(QLatin1String("egl"))) { is_egl = 1; return true; } #if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0) if (QGuiApplication::platformName().contains(QLatin1String("xcb"))) { is_egl = qgetenv("QT_XCB_GL_INTEGRATION") == "xcb_egl"; qDebug("xcb_egl=%d", is_egl); return !!is_egl; } #endif //5.5.0 #endif // we can use QOpenGLContext::currentContext()->nativeHandle().value<QEGLNativeContext>(). but gl context is required if (QOpenGLContext::currentContext()) is_egl = 0; return false; }
void AbstractPlatformContext::createContext(EGLContext shareContext) { const QByteArray eglExtensions = eglQueryString(eglDisplay(), EGL_EXTENSIONS); const QList<QByteArray> extensions = eglExtensions.split(' '); const bool haveRobustness = extensions.contains(QByteArrayLiteral("EGL_EXT_create_context_robustness")); const bool haveCreateContext = extensions.contains(QByteArrayLiteral("EGL_KHR_create_context")); EGLContext context = EGL_NO_CONTEXT; if (isOpenGLES()) { if (haveCreateContext && haveRobustness) { const EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT, EGL_TRUE, EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT, EGL_LOSE_CONTEXT_ON_RESET_EXT, EGL_NONE }; context = eglCreateContext(eglDisplay(), config(), shareContext, context_attribs); } if (context == EGL_NO_CONTEXT) { const EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; context = eglCreateContext(eglDisplay(), config(), shareContext, context_attribs); } } else { // Try to create a 3.1 core context if (m_format.majorVersion() >= 3 && haveCreateContext) { if (haveRobustness) { const int attribs[] = { EGL_CONTEXT_MAJOR_VERSION_KHR, m_format.majorVersion(), EGL_CONTEXT_MINOR_VERSION_KHR, m_format.minorVersion(), EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, EGL_LOSE_CONTEXT_ON_RESET_KHR, EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR | EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR, EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, m_format.profile() == QSurfaceFormat::CoreProfile ? EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR : EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR, EGL_NONE }; context = eglCreateContext(eglDisplay(), config(), shareContext, attribs); } if (context == EGL_NO_CONTEXT) { // try without robustness const EGLint attribs[] = { EGL_CONTEXT_MAJOR_VERSION_KHR, m_format.majorVersion(), EGL_CONTEXT_MINOR_VERSION_KHR, m_format.minorVersion(), EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR, EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, m_format.profile() == QSurfaceFormat::CoreProfile ? EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR : EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR, EGL_NONE }; context = eglCreateContext(eglDisplay(), config(), shareContext, attribs); } } if (context == EGL_NO_CONTEXT && haveRobustness && haveCreateContext) { const int attribs[] = { EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR, EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, EGL_LOSE_CONTEXT_ON_RESET_KHR, EGL_NONE }; context = eglCreateContext(eglDisplay(), config(), shareContext, attribs); } if (context == EGL_NO_CONTEXT) { // and last but not least: try without robustness const EGLint attribs[] = { EGL_NONE }; context = eglCreateContext(eglDisplay(), config(), shareContext, attribs); } } if (context == EGL_NO_CONTEXT) { return; } m_context = context; }