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