glamor.c revision 35c4bbdf
1/* 2 * Copyright © 2008,2011 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 * 23 * Authors: 24 * Eric Anholt <eric@anholt.net> 25 * Zhigang Gong <zhigang.gong@linux.intel.com> 26 * Chad Versace <chad.versace@linux.intel.com> 27 */ 28 29/** @file glamor.c 30 * This file covers the initialization and teardown of glamor, and has various 31 * functions not responsible for performing rendering. 32 */ 33 34#include <stdlib.h> 35 36#include "glamor_priv.h" 37#include "mipict.h" 38 39DevPrivateKeyRec glamor_screen_private_key; 40DevPrivateKeyRec glamor_pixmap_private_key; 41DevPrivateKeyRec glamor_gc_private_key; 42 43/** 44 * glamor_get_drawable_pixmap() returns a backing pixmap for a given drawable. 45 * 46 * @param drawable the drawable being requested. 47 * 48 * This function returns the backing pixmap for a drawable, whether it is a 49 * redirected window, unredirected window, or already a pixmap. Note that 50 * coordinate translation is needed when drawing to the backing pixmap of a 51 * redirected window, and the translation coordinates are provided by calling 52 * exaGetOffscreenPixmap() on the drawable. 53 */ 54PixmapPtr 55glamor_get_drawable_pixmap(DrawablePtr drawable) 56{ 57 if (drawable->type == DRAWABLE_WINDOW) 58 return drawable->pScreen->GetWindowPixmap((WindowPtr) drawable); 59 else 60 return (PixmapPtr) drawable; 61} 62 63static void 64glamor_init_pixmap_private_small(PixmapPtr pixmap, glamor_pixmap_private *pixmap_priv) 65{ 66 pixmap_priv->box.x1 = 0; 67 pixmap_priv->box.x2 = pixmap->drawable.width; 68 pixmap_priv->box.y1 = 0; 69 pixmap_priv->box.y2 = pixmap->drawable.height; 70 pixmap_priv->block_w = pixmap->drawable.width; 71 pixmap_priv->block_h = pixmap->drawable.height; 72 pixmap_priv->block_hcnt = 1; 73 pixmap_priv->block_wcnt = 1; 74 pixmap_priv->box_array = &pixmap_priv->box; 75 pixmap_priv->fbo_array = &pixmap_priv->fbo; 76} 77 78_X_EXPORT void 79glamor_set_pixmap_type(PixmapPtr pixmap, glamor_pixmap_type_t type) 80{ 81 glamor_pixmap_private *pixmap_priv; 82 83 pixmap_priv = glamor_get_pixmap_private(pixmap); 84 pixmap_priv->type = type; 85 glamor_init_pixmap_private_small(pixmap, pixmap_priv); 86} 87 88_X_EXPORT void 89glamor_set_pixmap_texture(PixmapPtr pixmap, unsigned int tex) 90{ 91 ScreenPtr screen = pixmap->drawable.pScreen; 92 glamor_pixmap_private *pixmap_priv; 93 glamor_screen_private *glamor_priv; 94 glamor_pixmap_fbo *fbo; 95 GLenum format; 96 97 glamor_priv = glamor_get_screen_private(screen); 98 pixmap_priv = glamor_get_pixmap_private(pixmap); 99 100 if (pixmap_priv->fbo) { 101 fbo = glamor_pixmap_detach_fbo(pixmap_priv); 102 glamor_destroy_fbo(glamor_priv, fbo); 103 } 104 105 format = gl_iformat_for_pixmap(pixmap); 106 fbo = glamor_create_fbo_from_tex(glamor_priv, pixmap->drawable.width, 107 pixmap->drawable.height, format, tex, 0); 108 109 if (fbo == NULL) { 110 ErrorF("XXX fail to create fbo.\n"); 111 return; 112 } 113 fbo->external = TRUE; 114 115 glamor_pixmap_attach_fbo(pixmap, fbo); 116} 117 118void 119glamor_set_screen_pixmap(PixmapPtr screen_pixmap, PixmapPtr *back_pixmap) 120{ 121 glamor_pixmap_private *pixmap_priv; 122 glamor_screen_private *glamor_priv; 123 124 glamor_priv = glamor_get_screen_private(screen_pixmap->drawable.pScreen); 125 pixmap_priv = glamor_get_pixmap_private(screen_pixmap); 126 glamor_priv->screen_fbo = pixmap_priv->fbo->fb; 127 128 pixmap_priv->fbo->width = screen_pixmap->drawable.width; 129 pixmap_priv->fbo->height = screen_pixmap->drawable.height; 130} 131 132uint32_t 133glamor_get_pixmap_texture(PixmapPtr pixmap) 134{ 135 glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap); 136 137 if (pixmap_priv->type != GLAMOR_TEXTURE_ONLY) 138 return 0; 139 140 return pixmap_priv->fbo->tex; 141} 142 143void 144glamor_bind_texture(glamor_screen_private *glamor_priv, GLenum texture, 145 glamor_pixmap_fbo *fbo, Bool destination_red) 146{ 147 glActiveTexture(texture); 148 glBindTexture(GL_TEXTURE_2D, fbo->tex); 149 150 /* If we're pulling data from a GL_RED texture, then whether we 151 * want to make it an A,0,0,0 result or a 0,0,0,R result depends 152 * on whether the destination is also a GL_RED texture. 153 * 154 * For GL_RED destinations, we need to leave the bits in the R 155 * channel. For all other destinations, we need to clear out the R 156 * channel so that it returns zero for R, G and B. 157 * 158 * Note that we're leaving the SWIZZLE_A value alone; for GL_RED 159 * destinations, that means we'll actually be returning R,0,0,R, 160 * but it doesn't matter as the bits in the alpha channel aren't 161 * going anywhere. 162 */ 163 164 /* Is the operand a GL_RED fbo? 165 */ 166 167 if (glamor_fbo_red_is_alpha(glamor_priv, fbo)) { 168 169 /* If destination is also GL_RED, then preserve the bits in 170 * the R channel */ 171 172 if (destination_red) 173 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED); 174 else 175 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_ZERO); 176 } 177} 178 179PixmapPtr 180glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth, 181 unsigned int usage) 182{ 183 PixmapPtr pixmap; 184 glamor_pixmap_private *pixmap_priv; 185 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 186 glamor_pixmap_fbo *fbo = NULL; 187 int pitch; 188 GLenum format; 189 190 if (w > 32767 || h > 32767) 191 return NullPixmap; 192 193 if ((usage == GLAMOR_CREATE_PIXMAP_CPU 194 || (usage == CREATE_PIXMAP_USAGE_GLYPH_PICTURE && 195 w <= glamor_priv->glyph_max_dim && 196 h <= glamor_priv->glyph_max_dim) 197 || (w == 0 && h == 0) 198 || !glamor_check_pixmap_fbo_depth(depth)) 199 || (!GLAMOR_TEXTURED_LARGE_PIXMAP && 200 !glamor_check_fbo_size(glamor_priv, w, h))) 201 return fbCreatePixmap(screen, w, h, depth, usage); 202 else 203 pixmap = fbCreatePixmap(screen, 0, 0, depth, usage); 204 205 pixmap_priv = glamor_get_pixmap_private(pixmap); 206 207 format = gl_iformat_for_pixmap(pixmap); 208 209 pitch = (((w * pixmap->drawable.bitsPerPixel + 7) / 8) + 3) & ~3; 210 screen->ModifyPixmapHeader(pixmap, w, h, 0, 0, pitch, NULL); 211 212 pixmap_priv->type = GLAMOR_TEXTURE_ONLY; 213 214 if (usage == GLAMOR_CREATE_PIXMAP_NO_TEXTURE) { 215 glamor_init_pixmap_private_small(pixmap, pixmap_priv); 216 return pixmap; 217 } 218 else if (usage == GLAMOR_CREATE_NO_LARGE || 219 glamor_check_fbo_size(glamor_priv, w, h)) 220 { 221 glamor_init_pixmap_private_small(pixmap, pixmap_priv); 222 fbo = glamor_create_fbo(glamor_priv, w, h, format, usage); 223 } else { 224 int tile_size = glamor_priv->max_fbo_size; 225 DEBUGF("Create LARGE pixmap %p width %d height %d, tile size %d\n", 226 pixmap, w, h, tile_size); 227 fbo = glamor_create_fbo_array(glamor_priv, w, h, format, usage, 228 tile_size, tile_size, pixmap_priv); 229 } 230 231 if (fbo == NULL) { 232 fbDestroyPixmap(pixmap); 233 return fbCreatePixmap(screen, w, h, depth, usage); 234 } 235 236 glamor_pixmap_attach_fbo(pixmap, fbo); 237 238 return pixmap; 239} 240 241void 242glamor_destroy_textured_pixmap(PixmapPtr pixmap) 243{ 244 if (pixmap->refcnt == 1) { 245#if GLAMOR_HAS_GBM 246 glamor_egl_destroy_pixmap_image(pixmap); 247#endif 248 glamor_pixmap_destroy_fbo(pixmap); 249 } 250} 251 252Bool 253glamor_destroy_pixmap(PixmapPtr pixmap) 254{ 255 glamor_destroy_textured_pixmap(pixmap); 256 return fbDestroyPixmap(pixmap); 257} 258 259void 260glamor_block_handler(ScreenPtr screen) 261{ 262 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 263 264 glamor_make_current(glamor_priv); 265 glamor_priv->tick++; 266 glFlush(); 267 glamor_fbo_expire(glamor_priv); 268} 269 270static void 271_glamor_block_handler(ScreenPtr screen, void *timeout, void *readmask) 272{ 273 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 274 275 screen->BlockHandler = glamor_priv->saved_procs.block_handler; 276 screen->BlockHandler(screen, timeout, readmask); 277 glamor_priv->saved_procs.block_handler = screen->BlockHandler; 278 screen->BlockHandler = _glamor_block_handler; 279 280 glamor_make_current(glamor_priv); 281 glFlush(); 282} 283 284static void 285glamor_set_debug_level(int *debug_level) 286{ 287 char *debug_level_string; 288 289 debug_level_string = getenv("GLAMOR_DEBUG"); 290 if (debug_level_string 291 && sscanf(debug_level_string, "%d", debug_level) == 1) 292 return; 293 *debug_level = 0; 294} 295 296int glamor_debug_level; 297 298void 299glamor_gldrawarrays_quads_using_indices(glamor_screen_private *glamor_priv, 300 unsigned count) 301{ 302 unsigned i; 303 304 /* For a single quad, don't bother with an index buffer. */ 305 if (count == 1) 306 goto fallback; 307 308 if (glamor_priv->ib_size < count) { 309 /* Basic GLES2 doesn't have any way to map buffer objects for 310 * writing, but it's long past time for drivers to have 311 * MapBufferRange. 312 */ 313 if (!glamor_priv->has_map_buffer_range) 314 goto fallback; 315 316 /* Lazy create the buffer name, and only bind it once since 317 * none of the glamor code binds it to anything else. 318 */ 319 if (!glamor_priv->ib) { 320 glGenBuffers(1, &glamor_priv->ib); 321 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, glamor_priv->ib); 322 } 323 324 /* For now, only support GL_UNSIGNED_SHORTs. */ 325 if (count > ((1 << 16) - 1) / 4) { 326 goto fallback; 327 } else { 328 uint16_t *data; 329 size_t size = count * 6 * sizeof(GLushort); 330 331 glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, NULL, GL_STATIC_DRAW); 332 data = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, 333 0, size, 334 GL_MAP_WRITE_BIT | 335 GL_MAP_INVALIDATE_BUFFER_BIT); 336 for (i = 0; i < count; i++) { 337 data[i * 6 + 0] = i * 4 + 0; 338 data[i * 6 + 1] = i * 4 + 1; 339 data[i * 6 + 2] = i * 4 + 2; 340 data[i * 6 + 3] = i * 4 + 0; 341 data[i * 6 + 4] = i * 4 + 2; 342 data[i * 6 + 5] = i * 4 + 3; 343 } 344 glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); 345 346 glamor_priv->ib_size = count; 347 glamor_priv->ib_type = GL_UNSIGNED_SHORT; 348 } 349 } 350 351 glDrawElements(GL_TRIANGLES, count * 6, glamor_priv->ib_type, NULL); 352 return; 353 354fallback: 355 for (i = 0; i < count; i++) 356 glDrawArrays(GL_TRIANGLE_FAN, i * 4, 4); 357} 358 359 360/** 361 * Creates any pixmaps used internally by glamor, since those can't be 362 * allocated at ScreenInit time. 363 */ 364static Bool 365glamor_create_screen_resources(ScreenPtr screen) 366{ 367 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 368 Bool ret = TRUE; 369 370 screen->CreateScreenResources = 371 glamor_priv->saved_procs.create_screen_resources; 372 if (screen->CreateScreenResources) 373 ret = screen->CreateScreenResources(screen); 374 screen->CreateScreenResources = glamor_create_screen_resources; 375 376 return ret; 377} 378 379static Bool 380glamor_check_instruction_count(int gl_version) 381{ 382 GLint max_native_alu_instructions; 383 384 /* Avoid using glamor if the reported instructions limit is too low, 385 * as this would cause glamor to fallback on sw due to large shaders 386 * which ends up being unbearably slow. 387 */ 388 if (gl_version < 30) { 389 if (!epoxy_has_gl_extension("GL_ARB_fragment_program")) { 390 ErrorF("GL_ARB_fragment_program required\n"); 391 return FALSE; 392 } 393 394 glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, 395 GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB, 396 &max_native_alu_instructions); 397 if (max_native_alu_instructions < GLAMOR_MIN_ALU_INSTRUCTIONS) { 398 LogMessage(X_WARNING, 399 "glamor requires at least %d instructions (%d reported)\n", 400 GLAMOR_MIN_ALU_INSTRUCTIONS, max_native_alu_instructions); 401 return FALSE; 402 } 403 } 404 405 return TRUE; 406} 407 408static void GLAPIENTRY 409glamor_debug_output_callback(GLenum source, 410 GLenum type, 411 GLuint id, 412 GLenum severity, 413 GLsizei length, 414 const GLchar *message, 415 const void *userParam) 416{ 417 ScreenPtr screen = (void *)userParam; 418 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 419 420 if (glamor_priv->suppress_gl_out_of_memory_logging && 421 source == GL_DEBUG_SOURCE_API && type == GL_DEBUG_TYPE_ERROR) { 422 return; 423 } 424 425 LogMessageVerb(X_ERROR, 0, "glamor%d: GL error: %*s\n", 426 screen->myNum, length, message); 427} 428 429/** 430 * Configures GL_ARB_debug_output to give us immediate callbacks when 431 * GL errors occur, so that we can log them. 432 */ 433static void 434glamor_setup_debug_output(ScreenPtr screen) 435{ 436 if (!epoxy_has_gl_extension("GL_ARB_debug_output")) 437 return; 438 439 glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); 440 /* Disable debugging messages other than GL API errors */ 441 glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, 442 GL_FALSE); 443 glDebugMessageControl(GL_DEBUG_SOURCE_API, 444 GL_DEBUG_TYPE_ERROR, 445 GL_DONT_CARE, 446 0, NULL, GL_TRUE); 447 glDebugMessageCallback(glamor_debug_output_callback, 448 screen); 449 450 /* If KHR_debug is present, all debug output is disabled by 451 * default on non-debug contexts. 452 */ 453 if (epoxy_has_gl_extension("GL_KHR_debug")) 454 glEnable(GL_DEBUG_OUTPUT); 455} 456 457/** Set up glamor for an already-configured GL context. */ 458Bool 459glamor_init(ScreenPtr screen, unsigned int flags) 460{ 461 glamor_screen_private *glamor_priv; 462 int gl_version; 463 int glsl_major, glsl_minor; 464 int max_viewport_size[2]; 465 const char *shading_version_string; 466 int shading_version_offset; 467 468 PictureScreenPtr ps = GetPictureScreenIfSet(screen); 469 470 if (flags & ~GLAMOR_VALID_FLAGS) { 471 ErrorF("glamor_init: Invalid flags %x\n", flags); 472 return FALSE; 473 } 474 glamor_priv = calloc(1, sizeof(*glamor_priv)); 475 if (glamor_priv == NULL) 476 return FALSE; 477 478 glamor_priv->flags = flags; 479 480 if (!dixRegisterPrivateKey(&glamor_screen_private_key, PRIVATE_SCREEN, 0)) { 481 LogMessage(X_WARNING, 482 "glamor%d: Failed to allocate screen private\n", 483 screen->myNum); 484 goto fail; 485 } 486 487 glamor_set_screen_private(screen, glamor_priv); 488 489 if (!dixRegisterPrivateKey(&glamor_pixmap_private_key, PRIVATE_PIXMAP, 490 sizeof(struct glamor_pixmap_private))) { 491 LogMessage(X_WARNING, 492 "glamor%d: Failed to allocate pixmap private\n", 493 screen->myNum); 494 goto fail; 495 } 496 497 if (!dixRegisterPrivateKey(&glamor_gc_private_key, PRIVATE_GC, 498 sizeof (glamor_gc_private))) { 499 LogMessage(X_WARNING, 500 "glamor%d: Failed to allocate gc private\n", 501 screen->myNum); 502 goto fail; 503 } 504 505 glamor_priv->saved_procs.close_screen = screen->CloseScreen; 506 screen->CloseScreen = glamor_close_screen; 507 508 /* If we are using egl screen, call egl screen init to 509 * register correct close screen function. */ 510 if (flags & GLAMOR_USE_EGL_SCREEN) { 511 glamor_egl_screen_init(screen, &glamor_priv->ctx); 512 } else { 513 if (!glamor_glx_screen_init(&glamor_priv->ctx)) 514 goto fail; 515 } 516 517 glamor_make_current(glamor_priv); 518 519 if (epoxy_is_desktop_gl()) 520 glamor_priv->gl_flavor = GLAMOR_GL_DESKTOP; 521 else 522 glamor_priv->gl_flavor = GLAMOR_GL_ES2; 523 524 gl_version = epoxy_gl_version(); 525 526 shading_version_string = (char *) glGetString(GL_SHADING_LANGUAGE_VERSION); 527 528 if (!shading_version_string) { 529 LogMessage(X_WARNING, 530 "glamor%d: Failed to get GLSL version\n", 531 screen->myNum); 532 goto fail; 533 } 534 535 shading_version_offset = 0; 536 if (strncmp("OpenGL ES GLSL ES ", shading_version_string, 18) == 0) 537 shading_version_offset = 18; 538 539 if (sscanf(shading_version_string + shading_version_offset, 540 "%i.%i", 541 &glsl_major, 542 &glsl_minor) != 2) { 543 LogMessage(X_WARNING, 544 "glamor%d: Failed to parse GLSL version string %s\n", 545 screen->myNum, shading_version_string); 546 goto fail; 547 } 548 glamor_priv->glsl_version = glsl_major * 100 + glsl_minor; 549 550 if (glamor_priv->gl_flavor == GLAMOR_GL_ES2) { 551 /* Force us back to the base version of our programs on an ES 552 * context, anyway. Basically glamor only uses desktop 1.20 553 * or 1.30 currently. 1.30's new features are also present in 554 * ES 3.0, but our glamor_program.c constructions use a lot of 555 * compatibility features (to reduce the diff between 1.20 and 556 * 1.30 programs). 557 */ 558 glamor_priv->glsl_version = 120; 559 } 560 561 /* We'd like to require GL_ARB_map_buffer_range or 562 * GL_OES_map_buffer_range, since it offers more information to 563 * the driver than plain old glMapBuffer() or glBufferSubData(). 564 * It's been supported on Mesa on the desktop since 2009 and on 565 * GLES2 since October 2012. It's supported on Apple's iOS 566 * drivers for SGX535 and A7, but apparently not on most Android 567 * devices (the OES extension spec wasn't released until June 568 * 2012). 569 * 570 * 82% of 0 A.D. players (desktop GL) submitting hardware reports 571 * have support for it, with most of the ones lacking it being on 572 * Windows with Intel 4-series (G45) graphics or older. 573 */ 574 if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) { 575 if (gl_version < 21) { 576 ErrorF("Require OpenGL version 2.1 or later.\n"); 577 goto fail; 578 } 579 580 if (!glamor_check_instruction_count(gl_version)) 581 goto fail; 582 } else { 583 if (gl_version < 20) { 584 ErrorF("Require Open GLES2.0 or later.\n"); 585 goto fail; 586 } 587 588 if (!epoxy_has_gl_extension("GL_EXT_texture_format_BGRA8888")) { 589 ErrorF("GL_EXT_texture_format_BGRA8888 required\n"); 590 goto fail; 591 } 592 } 593 594 glamor_priv->has_rw_pbo = FALSE; 595 if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) 596 glamor_priv->has_rw_pbo = TRUE; 597 598 glamor_priv->has_khr_debug = epoxy_has_gl_extension("GL_KHR_debug"); 599 glamor_priv->has_pack_invert = 600 epoxy_has_gl_extension("GL_MESA_pack_invert"); 601 glamor_priv->has_fbo_blit = 602 epoxy_has_gl_extension("GL_EXT_framebuffer_blit"); 603 glamor_priv->has_map_buffer_range = 604 epoxy_has_gl_extension("GL_ARB_map_buffer_range") || 605 epoxy_has_gl_extension("GL_EXT_map_buffer_range"); 606 glamor_priv->has_buffer_storage = 607 epoxy_has_gl_extension("GL_ARB_buffer_storage"); 608 glamor_priv->has_nv_texture_barrier = 609 epoxy_has_gl_extension("GL_NV_texture_barrier"); 610 glamor_priv->has_unpack_subimage = 611 glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP || 612 epoxy_gl_version() >= 30 || 613 epoxy_has_gl_extension("GL_EXT_unpack_subimage"); 614 glamor_priv->has_pack_subimage = 615 glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP || 616 epoxy_gl_version() >= 30 || 617 epoxy_has_gl_extension("GL_NV_pack_subimage"); 618 glamor_priv->has_vertex_array_object = 619 epoxy_has_gl_extension("GL_ARB_vertex_array_object"); 620 glamor_priv->has_dual_blend = 621 epoxy_has_gl_extension("GL_ARB_blend_func_extended"); 622 623 /* assume a core profile if we are GL 3.1 and don't have ARB_compatibility */ 624 glamor_priv->is_core_profile = 625 gl_version >= 31 && !epoxy_has_gl_extension("GL_ARB_compatibility"); 626 627 glamor_setup_debug_output(screen); 628 629 glamor_priv->use_quads = (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) && 630 !glamor_priv->is_core_profile; 631 632 /* Driver-specific hack: Avoid using GL_QUADS on VC4, where 633 * they'll be emulated more expensively than we can with our 634 * cached IB. 635 */ 636 if (strstr((char *)glGetString(GL_VENDOR), "Broadcom") && 637 strstr((char *)glGetString(GL_RENDERER), "VC4")) 638 glamor_priv->use_quads = FALSE; 639 640 glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &glamor_priv->max_fbo_size); 641 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glamor_priv->max_fbo_size); 642 glGetIntegerv(GL_MAX_VIEWPORT_DIMS, max_viewport_size); 643 glamor_priv->max_fbo_size = MIN(glamor_priv->max_fbo_size, max_viewport_size[0]); 644 glamor_priv->max_fbo_size = MIN(glamor_priv->max_fbo_size, max_viewport_size[1]); 645#ifdef MAX_FBO_SIZE 646 glamor_priv->max_fbo_size = MAX_FBO_SIZE; 647#endif 648 649 glamor_priv->one_channel_format = GL_ALPHA; 650 if (epoxy_has_gl_extension("GL_ARB_texture_rg") && epoxy_has_gl_extension("GL_ARB_texture_swizzle")) 651 glamor_priv->one_channel_format = GL_RED; 652 653 glamor_set_debug_level(&glamor_debug_level); 654 655 glamor_priv->saved_procs.create_screen_resources = 656 screen->CreateScreenResources; 657 screen->CreateScreenResources = glamor_create_screen_resources; 658 659 if (!glamor_font_init(screen)) 660 goto fail; 661 662 glamor_priv->saved_procs.block_handler = screen->BlockHandler; 663 screen->BlockHandler = _glamor_block_handler; 664 665 if (!glamor_composite_glyphs_init(screen)) { 666 ErrorF("Failed to initialize composite masks\n"); 667 goto fail; 668 } 669 670 glamor_priv->saved_procs.create_gc = screen->CreateGC; 671 screen->CreateGC = glamor_create_gc; 672 673 glamor_priv->saved_procs.create_pixmap = screen->CreatePixmap; 674 screen->CreatePixmap = glamor_create_pixmap; 675 676 glamor_priv->saved_procs.destroy_pixmap = screen->DestroyPixmap; 677 screen->DestroyPixmap = glamor_destroy_pixmap; 678 679 glamor_priv->saved_procs.get_spans = screen->GetSpans; 680 screen->GetSpans = glamor_get_spans; 681 682 glamor_priv->saved_procs.get_image = screen->GetImage; 683 screen->GetImage = glamor_get_image; 684 685 glamor_priv->saved_procs.change_window_attributes = 686 screen->ChangeWindowAttributes; 687 screen->ChangeWindowAttributes = glamor_change_window_attributes; 688 689 glamor_priv->saved_procs.copy_window = screen->CopyWindow; 690 screen->CopyWindow = glamor_copy_window; 691 692 glamor_priv->saved_procs.bitmap_to_region = screen->BitmapToRegion; 693 screen->BitmapToRegion = glamor_bitmap_to_region; 694 695 glamor_priv->saved_procs.composite = ps->Composite; 696 ps->Composite = glamor_composite; 697 698 glamor_priv->saved_procs.trapezoids = ps->Trapezoids; 699 ps->Trapezoids = glamor_trapezoids; 700 701 glamor_priv->saved_procs.triangles = ps->Triangles; 702 ps->Triangles = glamor_triangles; 703 704 glamor_priv->saved_procs.addtraps = ps->AddTraps; 705 ps->AddTraps = glamor_add_traps; 706 707 glamor_priv->saved_procs.composite_rects = ps->CompositeRects; 708 ps->CompositeRects = glamor_composite_rectangles; 709 710 glamor_priv->saved_procs.glyphs = ps->Glyphs; 711 ps->Glyphs = glamor_composite_glyphs; 712 713 glamor_init_vbo(screen); 714 glamor_init_pixmap_fbo(screen); 715 glamor_init_finish_access_shaders(screen); 716 717#ifdef GLAMOR_GRADIENT_SHADER 718 glamor_init_gradient_shader(screen); 719#endif 720 glamor_pixmap_init(screen); 721 glamor_sync_init(screen); 722 723 glamor_priv->screen = screen; 724 725 return TRUE; 726 727 fail: 728 free(glamor_priv); 729 glamor_set_screen_private(screen, NULL); 730 return FALSE; 731} 732 733static void 734glamor_release_screen_priv(ScreenPtr screen) 735{ 736 glamor_screen_private *glamor_priv; 737 738 glamor_priv = glamor_get_screen_private(screen); 739 glamor_fini_vbo(screen); 740 glamor_fini_pixmap_fbo(screen); 741 glamor_pixmap_fini(screen); 742 free(glamor_priv); 743 744 glamor_set_screen_private(screen, NULL); 745} 746 747Bool 748glamor_close_screen(ScreenPtr screen) 749{ 750 glamor_screen_private *glamor_priv; 751 PixmapPtr screen_pixmap; 752 PictureScreenPtr ps = GetPictureScreenIfSet(screen); 753 754 glamor_priv = glamor_get_screen_private(screen); 755 glamor_sync_close(screen); 756 glamor_composite_glyphs_fini(screen); 757 screen->CloseScreen = glamor_priv->saved_procs.close_screen; 758 screen->CreateScreenResources = 759 glamor_priv->saved_procs.create_screen_resources; 760 761 screen->CreateGC = glamor_priv->saved_procs.create_gc; 762 screen->CreatePixmap = glamor_priv->saved_procs.create_pixmap; 763 screen->DestroyPixmap = glamor_priv->saved_procs.destroy_pixmap; 764 screen->GetSpans = glamor_priv->saved_procs.get_spans; 765 screen->ChangeWindowAttributes = 766 glamor_priv->saved_procs.change_window_attributes; 767 screen->CopyWindow = glamor_priv->saved_procs.copy_window; 768 screen->BitmapToRegion = glamor_priv->saved_procs.bitmap_to_region; 769 screen->BlockHandler = glamor_priv->saved_procs.block_handler; 770 771 ps->Composite = glamor_priv->saved_procs.composite; 772 ps->Trapezoids = glamor_priv->saved_procs.trapezoids; 773 ps->Triangles = glamor_priv->saved_procs.triangles; 774 ps->CompositeRects = glamor_priv->saved_procs.composite_rects; 775 ps->Glyphs = glamor_priv->saved_procs.glyphs; 776 777 screen_pixmap = screen->GetScreenPixmap(screen); 778 glamor_pixmap_destroy_fbo(screen_pixmap); 779 780 glamor_release_screen_priv(screen); 781 782 return screen->CloseScreen(screen); 783} 784 785void 786glamor_fini(ScreenPtr screen) 787{ 788 /* Do nothing currently. */ 789} 790 791void 792glamor_enable_dri3(ScreenPtr screen) 793{ 794 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 795 796 glamor_priv->dri3_enabled = TRUE; 797} 798 799Bool 800glamor_supports_pixmap_import_export(ScreenPtr screen) 801{ 802 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 803 804 return glamor_priv->dri3_enabled; 805} 806 807_X_EXPORT int 808glamor_fd_from_pixmap(ScreenPtr screen, 809 PixmapPtr pixmap, CARD16 *stride, CARD32 *size) 810{ 811 glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap); 812 glamor_screen_private *glamor_priv = 813 glamor_get_screen_private(pixmap->drawable.pScreen); 814 815 if (!glamor_priv->dri3_enabled) 816 return -1; 817 switch (pixmap_priv->type) { 818 case GLAMOR_TEXTURE_DRM: 819 case GLAMOR_TEXTURE_ONLY: 820 if (!glamor_pixmap_ensure_fbo(pixmap, GL_RGBA, 0)) 821 return -1; 822 return glamor_egl_dri3_fd_name_from_tex(screen, 823 pixmap, 824 pixmap_priv->fbo->tex, 825 FALSE, stride, size); 826 default: 827 break; 828 } 829 return -1; 830} 831 832int 833glamor_name_from_pixmap(PixmapPtr pixmap, CARD16 *stride, CARD32 *size) 834{ 835 glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap); 836 glamor_screen_private *glamor_priv = 837 glamor_get_screen_private(pixmap->drawable.pScreen); 838 839 if (!glamor_priv->dri3_enabled) 840 return -1; 841 switch (pixmap_priv->type) { 842 case GLAMOR_TEXTURE_DRM: 843 case GLAMOR_TEXTURE_ONLY: 844 if (!glamor_pixmap_ensure_fbo(pixmap, GL_RGBA, 0)) 845 return -1; 846 return glamor_egl_dri3_fd_name_from_tex(pixmap->drawable.pScreen, 847 pixmap, 848 pixmap_priv->fbo->tex, 849 TRUE, stride, size); 850 default: 851 break; 852 } 853 return -1; 854} 855 856void 857glamor_finish(ScreenPtr screen) 858{ 859 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 860 861 glamor_make_current(glamor_priv); 862 glFinish(); 863} 864