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