static Bool glamor_check_instruction_count(int gl_version) { GLint max_native_alu_instructions; /* Avoid using glamor if the reported instructions limit is too low, * as this would cause glamor to fallback on sw due to large shaders * which ends up being unbearably slow. */ if (gl_version < 30) { if (!epoxy_has_gl_extension("GL_ARB_fragment_program")) { ErrorF("GL_ARB_fragment_program required\n"); return FALSE; } glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB, &max_native_alu_instructions); if (max_native_alu_instructions < GLAMOR_MIN_ALU_INSTRUCTIONS) { LogMessage(X_WARNING, "glamor requires at least %d instructions (%d reported)\n", GLAMOR_MIN_ALU_INSTRUCTIONS, max_native_alu_instructions); return FALSE; } } return TRUE; }
static void gsk_gl_profiler_init (GskGLProfiler *self) { glGenQueries (N_QUERIES, self->gl_queries); self->first_frame = TRUE; self->has_timer = epoxy_has_gl_extension ("GL_ARB_timer_query"); }
static void xwl_drm_init_egl(struct xwl_screen *xwl_screen) { EGLint major, minor; const char *version; if (xwl_screen->egl_display) return; xwl_screen->expecting_event--; xwl_screen->gbm = gbm_create_device(xwl_screen->drm_fd); if (xwl_screen->gbm == NULL) { ErrorF("couldn't get display device\n"); return; } xwl_screen->egl_display = eglGetDisplay(xwl_screen->gbm); if (xwl_screen->egl_display == EGL_NO_DISPLAY) { ErrorF("eglGetDisplay() failed\n"); return; } eglBindAPI(EGL_OPENGL_API); if (!eglInitialize(xwl_screen->egl_display, &major, &minor)) { ErrorF("eglInitialize() failed\n"); return; } version = eglQueryString(xwl_screen->egl_display, EGL_VERSION); ErrorF("glamor: EGL version %s:\n", version); xwl_screen->egl_context = eglCreateContext(xwl_screen->egl_display, NULL, EGL_NO_CONTEXT, NULL); if (xwl_screen->egl_context == EGL_NO_CONTEXT) { ErrorF("Failed to create EGL context\n"); return; } if (!eglMakeCurrent(xwl_screen->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, xwl_screen->egl_context)) { ErrorF("Failed to make EGL context current\n"); return; } if (!epoxy_has_gl_extension("GL_OES_EGL_image")) { ErrorF("GL_OES_EGL_image not available\n"); return; } return; }
/** * Configures GL_ARB_debug_output to give us immediate callbacks when * GL errors occur, so that we can log them. */ static void glamor_setup_debug_output(ScreenPtr screen) { if (!epoxy_has_gl_extension("GL_ARB_debug_output")) return; glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); /* Disable debugging messages other than GL API errors */ glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_FALSE); glDebugMessageControl(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_ERROR, GL_DONT_CARE, 0, NULL, GL_TRUE); glDebugMessageCallback(glamor_debug_output_callback, screen); /* If KHR_debug is present, all debug output is disabled by * default on non-debug contexts. */ if (epoxy_has_gl_extension("GL_KHR_debug")) glEnable(GL_DEBUG_OUTPUT); }
/** Set up glamor for an already-configured GL context. */ Bool glamor_init(ScreenPtr screen, unsigned int flags) { glamor_screen_private *glamor_priv; int gl_version; int max_viewport_size[2]; #ifdef RENDER PictureScreenPtr ps = GetPictureScreenIfSet(screen); #endif if (flags & ~GLAMOR_VALID_FLAGS) { ErrorF("glamor_init: Invalid flags %x\n", flags); return FALSE; } glamor_priv = calloc(1, sizeof(*glamor_priv)); if (glamor_priv == NULL) return FALSE; glamor_priv->flags = flags; if (!dixRegisterPrivateKey(&glamor_screen_private_key, PRIVATE_SCREEN, 0)) { LogMessage(X_WARNING, "glamor%d: Failed to allocate screen private\n", screen->myNum); goto fail; } glamor_set_screen_private(screen, glamor_priv); if (!dixRegisterPrivateKey(&glamor_pixmap_private_key, PRIVATE_PIXMAP, 0)) { LogMessage(X_WARNING, "glamor%d: Failed to allocate pixmap private\n", screen->myNum); goto fail; } if (!dixRegisterPrivateKey(&glamor_gc_private_key, PRIVATE_GC, sizeof (glamor_gc_private))) { LogMessage(X_WARNING, "glamor%d: Failed to allocate gc private\n", screen->myNum); goto fail; } if (epoxy_is_desktop_gl()) glamor_priv->gl_flavor = GLAMOR_GL_DESKTOP; else glamor_priv->gl_flavor = GLAMOR_GL_ES2; gl_version = epoxy_gl_version(); /* Would be nice to have a cleaner test for GLSL 1.30 support, * but for now this should suffice */ if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP && gl_version >= 30) glamor_priv->glsl_version = 130; else glamor_priv->glsl_version = 120; /* We'd like to require GL_ARB_map_buffer_range or * GL_OES_map_buffer_range, since it offers more information to * the driver than plain old glMapBuffer() or glBufferSubData(). * It's been supported on Mesa on the desktop since 2009 and on * GLES2 since October 2012. It's supported on Apple's iOS * drivers for SGX535 and A7, but apparently not on most Android * devices (the OES extension spec wasn't released until June * 2012). * * 82% of 0 A.D. players (desktop GL) submitting hardware reports * have support for it, with most of the ones lacking it being on * Windows with Intel 4-series (G45) graphics or older. */ if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) { if (gl_version < 21) { ErrorF("Require OpenGL version 2.1 or later.\n"); goto fail; } } else { if (gl_version < 20) { ErrorF("Require Open GLES2.0 or later.\n"); goto fail; } if (!epoxy_has_gl_extension("GL_EXT_texture_format_BGRA8888")) { ErrorF("GL_EXT_texture_format_BGRA8888 required\n"); goto fail; } } glamor_priv->has_rw_pbo = FALSE; if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) glamor_priv->has_rw_pbo = TRUE; glamor_priv->has_khr_debug = epoxy_has_gl_extension("GL_KHR_debug"); glamor_priv->has_pack_invert = epoxy_has_gl_extension("GL_MESA_pack_invert"); glamor_priv->has_fbo_blit = epoxy_has_gl_extension("GL_EXT_framebuffer_blit"); glamor_priv->has_map_buffer_range = epoxy_has_gl_extension("GL_ARB_map_buffer_range"); glamor_priv->has_buffer_storage = epoxy_has_gl_extension("GL_ARB_buffer_storage"); glamor_priv->has_nv_texture_barrier = epoxy_has_gl_extension("GL_NV_texture_barrier"); glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &glamor_priv->max_fbo_size); glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glamor_priv->max_fbo_size); glGetIntegerv(GL_MAX_VIEWPORT_DIMS, max_viewport_size); glamor_priv->max_fbo_size = MIN(glamor_priv->max_fbo_size, max_viewport_size[0]); glamor_priv->max_fbo_size = MIN(glamor_priv->max_fbo_size, max_viewport_size[1]); #ifdef MAX_FBO_SIZE glamor_priv->max_fbo_size = MAX_FBO_SIZE; #endif glamor_set_debug_level(&glamor_debug_level); /* If we are using egl screen, call egl screen init to * register correct close screen function. */ if (flags & GLAMOR_USE_EGL_SCREEN) { glamor_egl_screen_init(screen, &glamor_priv->ctx); } else { if (!glamor_glx_screen_init(&glamor_priv->ctx)) goto fail; } glamor_priv->saved_procs.close_screen = screen->CloseScreen; screen->CloseScreen = glamor_close_screen; glamor_priv->saved_procs.create_screen_resources = screen->CreateScreenResources; screen->CreateScreenResources = glamor_create_screen_resources; if (!glamor_font_init(screen)) goto fail; if (flags & GLAMOR_USE_SCREEN) { if (!RegisterBlockAndWakeupHandlers(_glamor_block_handler, _glamor_wakeup_handler, glamor_priv)) { goto fail; } glamor_priv->saved_procs.create_gc = screen->CreateGC; screen->CreateGC = glamor_create_gc; glamor_priv->saved_procs.create_pixmap = screen->CreatePixmap; screen->CreatePixmap = glamor_create_pixmap; glamor_priv->saved_procs.destroy_pixmap = screen->DestroyPixmap; screen->DestroyPixmap = glamor_destroy_pixmap; glamor_priv->saved_procs.get_spans = screen->GetSpans; screen->GetSpans = glamor_get_spans; glamor_priv->saved_procs.get_image = screen->GetImage; screen->GetImage = glamor_get_image; glamor_priv->saved_procs.change_window_attributes = screen->ChangeWindowAttributes; screen->ChangeWindowAttributes = glamor_change_window_attributes; glamor_priv->saved_procs.copy_window = screen->CopyWindow; screen->CopyWindow = glamor_copy_window; glamor_priv->saved_procs.bitmap_to_region = screen->BitmapToRegion; screen->BitmapToRegion = glamor_bitmap_to_region; } #ifdef RENDER if (flags & GLAMOR_USE_PICTURE_SCREEN) { glamor_priv->saved_procs.composite = ps->Composite; ps->Composite = glamor_composite; glamor_priv->saved_procs.trapezoids = ps->Trapezoids; ps->Trapezoids = glamor_trapezoids; glamor_priv->saved_procs.triangles = ps->Triangles; ps->Triangles = glamor_triangles; glamor_priv->saved_procs.addtraps = ps->AddTraps; ps->AddTraps = glamor_add_traps; } glamor_priv->saved_procs.composite_rects = ps->CompositeRects; ps->CompositeRects = glamor_composite_rectangles; glamor_priv->saved_procs.glyphs = ps->Glyphs; ps->Glyphs = glamor_glyphs; glamor_priv->saved_procs.unrealize_glyph = ps->UnrealizeGlyph; ps->UnrealizeGlyph = glamor_glyph_unrealize; glamor_priv->saved_procs.create_picture = ps->CreatePicture; ps->CreatePicture = glamor_create_picture; glamor_priv->saved_procs.destroy_picture = ps->DestroyPicture; ps->DestroyPicture = glamor_destroy_picture; glamor_init_composite_shaders(screen); #endif glamor_priv->saved_procs.set_window_pixmap = screen->SetWindowPixmap; screen->SetWindowPixmap = glamor_set_window_pixmap; glamor_init_vbo(screen); glamor_init_pixmap_fbo(screen); #ifdef GLAMOR_TRAPEZOID_SHADER glamor_init_trapezoid_shader(screen); #endif glamor_init_finish_access_shaders(screen); #ifdef GLAMOR_GRADIENT_SHADER glamor_init_gradient_shader(screen); #endif glamor_pixmap_init(screen); glamor_glyphs_init(screen); glamor_sync_init(screen); glamor_priv->screen = screen; return TRUE; fail: free(glamor_priv); glamor_set_screen_private(screen, NULL); return FALSE; }
/** Set up glamor for an already-configured GL context. */ Bool glamor_init(ScreenPtr screen, unsigned int flags) { glamor_screen_private *glamor_priv; int gl_version; int glsl_major, glsl_minor; int max_viewport_size[2]; const char *shading_version_string; int shading_version_offset; PictureScreenPtr ps = GetPictureScreenIfSet(screen); if (flags & ~GLAMOR_VALID_FLAGS) { ErrorF("glamor_init: Invalid flags %x\n", flags); return FALSE; } glamor_priv = calloc(1, sizeof(*glamor_priv)); if (glamor_priv == NULL) return FALSE; glamor_priv->flags = flags; if (!dixRegisterPrivateKey(&glamor_screen_private_key, PRIVATE_SCREEN, 0)) { LogMessage(X_WARNING, "glamor%d: Failed to allocate screen private\n", screen->myNum); goto fail; } glamor_set_screen_private(screen, glamor_priv); if (!dixRegisterPrivateKey(&glamor_pixmap_private_key, PRIVATE_PIXMAP, sizeof(struct glamor_pixmap_private))) { LogMessage(X_WARNING, "glamor%d: Failed to allocate pixmap private\n", screen->myNum); goto fail; } if (!dixRegisterPrivateKey(&glamor_gc_private_key, PRIVATE_GC, sizeof (glamor_gc_private))) { LogMessage(X_WARNING, "glamor%d: Failed to allocate gc private\n", screen->myNum); goto fail; } glamor_priv->saved_procs.close_screen = screen->CloseScreen; screen->CloseScreen = glamor_close_screen; /* If we are using egl screen, call egl screen init to * register correct close screen function. */ if (flags & GLAMOR_USE_EGL_SCREEN) { glamor_egl_screen_init(screen, &glamor_priv->ctx); } else { if (!glamor_glx_screen_init(&glamor_priv->ctx)) goto fail; } glamor_make_current(glamor_priv); if (epoxy_is_desktop_gl()) glamor_priv->gl_flavor = GLAMOR_GL_DESKTOP; else glamor_priv->gl_flavor = GLAMOR_GL_ES2; gl_version = epoxy_gl_version(); shading_version_string = (char *) glGetString(GL_SHADING_LANGUAGE_VERSION); if (!shading_version_string) { LogMessage(X_WARNING, "glamor%d: Failed to get GLSL version\n", screen->myNum); goto fail; } shading_version_offset = 0; if (strncmp("OpenGL ES GLSL ES ", shading_version_string, 18) == 0) shading_version_offset = 18; if (sscanf(shading_version_string + shading_version_offset, "%i.%i", &glsl_major, &glsl_minor) != 2) { LogMessage(X_WARNING, "glamor%d: Failed to parse GLSL version string %s\n", screen->myNum, shading_version_string); goto fail; } glamor_priv->glsl_version = glsl_major * 100 + glsl_minor; if (glamor_priv->gl_flavor == GLAMOR_GL_ES2) { /* Force us back to the base version of our programs on an ES * context, anyway. Basically glamor only uses desktop 1.20 * or 1.30 currently. 1.30's new features are also present in * ES 3.0, but our glamor_program.c constructions use a lot of * compatibility features (to reduce the diff between 1.20 and * 1.30 programs). */ glamor_priv->glsl_version = 120; } /* We'd like to require GL_ARB_map_buffer_range or * GL_OES_map_buffer_range, since it offers more information to * the driver than plain old glMapBuffer() or glBufferSubData(). * It's been supported on Mesa on the desktop since 2009 and on * GLES2 since October 2012. It's supported on Apple's iOS * drivers for SGX535 and A7, but apparently not on most Android * devices (the OES extension spec wasn't released until June * 2012). * * 82% of 0 A.D. players (desktop GL) submitting hardware reports * have support for it, with most of the ones lacking it being on * Windows with Intel 4-series (G45) graphics or older. */ if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) { if (gl_version < 21) { ErrorF("Require OpenGL version 2.1 or later.\n"); goto fail; } if (!glamor_check_instruction_count(gl_version)) goto fail; } else { if (gl_version < 20) { ErrorF("Require Open GLES2.0 or later.\n"); goto fail; } if (!epoxy_has_gl_extension("GL_EXT_texture_format_BGRA8888")) { ErrorF("GL_EXT_texture_format_BGRA8888 required\n"); goto fail; } } glamor_priv->has_rw_pbo = FALSE; if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) glamor_priv->has_rw_pbo = TRUE; glamor_priv->has_khr_debug = epoxy_has_gl_extension("GL_KHR_debug"); glamor_priv->has_pack_invert = epoxy_has_gl_extension("GL_MESA_pack_invert"); glamor_priv->has_fbo_blit = epoxy_has_gl_extension("GL_EXT_framebuffer_blit"); glamor_priv->has_map_buffer_range = epoxy_has_gl_extension("GL_ARB_map_buffer_range") || epoxy_has_gl_extension("GL_EXT_map_buffer_range"); glamor_priv->has_buffer_storage = epoxy_has_gl_extension("GL_ARB_buffer_storage"); glamor_priv->has_nv_texture_barrier = epoxy_has_gl_extension("GL_NV_texture_barrier"); glamor_priv->has_unpack_subimage = glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP || epoxy_gl_version() >= 30 || epoxy_has_gl_extension("GL_EXT_unpack_subimage"); glamor_priv->has_pack_subimage = glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP || epoxy_gl_version() >= 30 || epoxy_has_gl_extension("GL_NV_pack_subimage"); glamor_priv->has_vertex_array_object = epoxy_has_gl_extension("GL_ARB_vertex_array_object"); glamor_priv->has_dual_blend = epoxy_has_gl_extension("GL_ARB_blend_func_extended"); /* assume a core profile if we are GL 3.1 and don't have ARB_compatibility */ glamor_priv->is_core_profile = gl_version >= 31 && !epoxy_has_gl_extension("GL_ARB_compatibility"); glamor_setup_debug_output(screen); glamor_priv->use_quads = (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) && !glamor_priv->is_core_profile; /* Driver-specific hack: Avoid using GL_QUADS on VC4, where * they'll be emulated more expensively than we can with our * cached IB. */ if (strstr((char *)glGetString(GL_VENDOR), "Broadcom") && strstr((char *)glGetString(GL_RENDERER), "VC4")) glamor_priv->use_quads = FALSE; glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &glamor_priv->max_fbo_size); glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glamor_priv->max_fbo_size); glGetIntegerv(GL_MAX_VIEWPORT_DIMS, max_viewport_size); glamor_priv->max_fbo_size = MIN(glamor_priv->max_fbo_size, max_viewport_size[0]); glamor_priv->max_fbo_size = MIN(glamor_priv->max_fbo_size, max_viewport_size[1]); #ifdef MAX_FBO_SIZE glamor_priv->max_fbo_size = MAX_FBO_SIZE; #endif glamor_priv->one_channel_format = GL_ALPHA; if (epoxy_has_gl_extension("GL_ARB_texture_rg") && epoxy_has_gl_extension("GL_ARB_texture_swizzle")) glamor_priv->one_channel_format = GL_RED; glamor_set_debug_level(&glamor_debug_level); glamor_priv->saved_procs.create_screen_resources = screen->CreateScreenResources; screen->CreateScreenResources = glamor_create_screen_resources; if (!glamor_font_init(screen)) goto fail; glamor_priv->saved_procs.block_handler = screen->BlockHandler; screen->BlockHandler = _glamor_block_handler; if (!glamor_composite_glyphs_init(screen)) { ErrorF("Failed to initialize composite masks\n"); goto fail; } glamor_priv->saved_procs.create_gc = screen->CreateGC; screen->CreateGC = glamor_create_gc; glamor_priv->saved_procs.create_pixmap = screen->CreatePixmap; screen->CreatePixmap = glamor_create_pixmap; glamor_priv->saved_procs.destroy_pixmap = screen->DestroyPixmap; screen->DestroyPixmap = glamor_destroy_pixmap; glamor_priv->saved_procs.get_spans = screen->GetSpans; screen->GetSpans = glamor_get_spans; glamor_priv->saved_procs.get_image = screen->GetImage; screen->GetImage = glamor_get_image; glamor_priv->saved_procs.change_window_attributes = screen->ChangeWindowAttributes; screen->ChangeWindowAttributes = glamor_change_window_attributes; glamor_priv->saved_procs.copy_window = screen->CopyWindow; screen->CopyWindow = glamor_copy_window; glamor_priv->saved_procs.bitmap_to_region = screen->BitmapToRegion; screen->BitmapToRegion = glamor_bitmap_to_region; glamor_priv->saved_procs.composite = ps->Composite; ps->Composite = glamor_composite; glamor_priv->saved_procs.trapezoids = ps->Trapezoids; ps->Trapezoids = glamor_trapezoids; glamor_priv->saved_procs.triangles = ps->Triangles; ps->Triangles = glamor_triangles; glamor_priv->saved_procs.addtraps = ps->AddTraps; ps->AddTraps = glamor_add_traps; glamor_priv->saved_procs.composite_rects = ps->CompositeRects; ps->CompositeRects = glamor_composite_rectangles; glamor_priv->saved_procs.glyphs = ps->Glyphs; ps->Glyphs = glamor_composite_glyphs; glamor_init_vbo(screen); glamor_init_pixmap_fbo(screen); glamor_init_finish_access_shaders(screen); #ifdef GLAMOR_GRADIENT_SHADER glamor_init_gradient_shader(screen); #endif glamor_pixmap_init(screen); glamor_sync_init(screen); glamor_priv->screen = screen; return TRUE; fail: free(glamor_priv); glamor_set_screen_private(screen, NULL); return FALSE; }
struct ephyr_glamor * ephyr_glamor_glx_screen_init(xcb_window_t win) { int (*oldErrorHandler) (Display *, XErrorEvent *); static const float position[] = { -1, -1, 1, -1, 1, 1, -1, 1, 0, 1, 1, 1, 1, 0, 0, 0, }; GLint old_vao; GLXContext ctx; struct ephyr_glamor *glamor; GLXWindow glx_win; glamor = calloc(1, sizeof(struct ephyr_glamor)); if (!glamor) { FatalError("malloc"); return NULL; } glx_win = glXCreateWindow(dpy, fb_config, win, NULL); if (ephyr_glamor_gles2) { static const int context_attribs[] = { GLX_CONTEXT_MAJOR_VERSION_ARB, 2, GLX_CONTEXT_MINOR_VERSION_ARB, 0, GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_ES_PROFILE_BIT_EXT, 0, }; if (epoxy_has_glx_extension(dpy, DefaultScreen(dpy), "GLX_EXT_create_context_es2_profile")) { ctx = glXCreateContextAttribsARB(dpy, fb_config, NULL, True, context_attribs); } else { FatalError("Xephyr -glamor_gles2 rquires " "GLX_EXT_create_context_es2_profile\n"); } } else { if (epoxy_has_glx_extension(dpy, DefaultScreen(dpy), "GLX_ARB_create_context")) { static const int context_attribs[] = { GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, GLX_CONTEXT_MAJOR_VERSION_ARB, GLAMOR_GL_CORE_VER_MAJOR, GLX_CONTEXT_MINOR_VERSION_ARB, GLAMOR_GL_CORE_VER_MINOR, 0, }; oldErrorHandler = XSetErrorHandler(ephyr_glx_error_handler); ctx = glXCreateContextAttribsARB(dpy, fb_config, NULL, True, context_attribs); XSync(dpy, False); XSetErrorHandler(oldErrorHandler); } else { ctx = NULL; } if (!ctx) ctx = glXCreateContext(dpy, visual_info, NULL, True); } if (ctx == NULL) FatalError("glXCreateContext failed\n"); if (!glXMakeCurrent(dpy, glx_win, ctx)) FatalError("glXMakeCurrent failed\n"); glamor->ctx = ctx; glamor->win = win; glamor->glx_win = glx_win; ephyr_glamor_setup_texturing_shader(glamor); if (epoxy_has_gl_extension("GL_ARB_vertex_array_object")) { glGenVertexArrays(1, &glamor->vao); glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &old_vao); glBindVertexArray(glamor->vao); } else glamor->vao = 0; glGenBuffers(1, &glamor->vbo); glBindBuffer(GL_ARRAY_BUFFER, glamor->vbo); glBufferData(GL_ARRAY_BUFFER, sizeof (position), position, GL_STATIC_DRAW); if (glamor->vao) { ephyr_glamor_set_vertices(glamor); glBindVertexArray(old_vao); } else glBindBuffer(GL_ARRAY_BUFFER, 0); return glamor; }