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