1/* 2 * Mesa 3-D graphics library 3 * 4 * Copyright 2009, VMware, Inc. 5 * All Rights Reserved. 6 * Copyright (C) 2010 LunarG Inc. 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the "Software"), 10 * to deal in the Software without restriction, including without limitation 11 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 * and/or sell copies of the Software, and to permit persons to whom the 13 * Software is furnished to do so, subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice shall be included 16 * in all copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 22 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 23 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24 * OTHER DEALINGS IN THE SOFTWARE. 25 * 26 * Authors: 27 * Keith Whitwell <keithw@vmware.com> Jakob Bornecrantz 28 * <wallbraker@gmail.com> Chia-I Wu <olv@lunarg.com> 29 */ 30 31#include <xf86drm.h> 32#include "GL/mesa_glinterop.h" 33#include "util/disk_cache.h" 34#include "util/u_memory.h" 35#include "util/u_inlines.h" 36#include "util/format/u_format.h" 37#include "util/u_debug.h" 38#include "frontend/drm_driver.h" 39#include "state_tracker/st_cb_bufferobjects.h" 40#include "state_tracker/st_cb_fbo.h" 41#include "state_tracker/st_cb_texture.h" 42#include "state_tracker/st_texture.h" 43#include "state_tracker/st_context.h" 44#include "pipe-loader/pipe_loader.h" 45#include "main/bufferobj.h" 46#include "main/texobj.h" 47 48#include "dri_util.h" 49 50#include "dri_helpers.h" 51#include "dri_drawable.h" 52#include "dri_query_renderer.h" 53 54#include "drm-uapi/drm_fourcc.h" 55 56struct dri2_buffer 57{ 58 __DRIbuffer base; 59 struct pipe_resource *resource; 60}; 61 62static inline struct dri2_buffer * 63dri2_buffer(__DRIbuffer * driBufferPriv) 64{ 65 return (struct dri2_buffer *) driBufferPriv; 66} 67 68/** 69 * DRI2 flush extension. 70 */ 71static void 72dri2_flush_drawable(__DRIdrawable *dPriv) 73{ 74 dri_flush(dPriv->driContextPriv, dPriv, __DRI2_FLUSH_DRAWABLE, -1); 75} 76 77static void 78dri2_invalidate_drawable(__DRIdrawable *dPriv) 79{ 80 struct dri_drawable *drawable = dri_drawable(dPriv); 81 82 dri2InvalidateDrawable(dPriv); 83 drawable->dPriv->lastStamp = drawable->dPriv->dri2.stamp; 84 drawable->texture_mask = 0; 85 86 p_atomic_inc(&drawable->base.stamp); 87} 88 89static const __DRI2flushExtension dri2FlushExtension = { 90 .base = { __DRI2_FLUSH, 4 }, 91 92 .flush = dri2_flush_drawable, 93 .invalidate = dri2_invalidate_drawable, 94 .flush_with_flags = dri_flush, 95}; 96 97/** 98 * Retrieve __DRIbuffer from the DRI loader. 99 */ 100static __DRIbuffer * 101dri2_drawable_get_buffers(struct dri_drawable *drawable, 102 const enum st_attachment_type *atts, 103 unsigned *count) 104{ 105 __DRIdrawable *dri_drawable = drawable->dPriv; 106 const __DRIdri2LoaderExtension *loader = drawable->sPriv->dri2.loader; 107 boolean with_format; 108 __DRIbuffer *buffers; 109 int num_buffers; 110 unsigned attachments[__DRI_BUFFER_COUNT]; 111 unsigned num_attachments, i; 112 113 assert(loader); 114 assert(*count <= __DRI_BUFFER_COUNT); 115 with_format = dri_with_format(drawable->sPriv); 116 117 num_attachments = 0; 118 119 /* for Xserver 1.6.0 (DRI2 version 1) we always need to ask for the front */ 120 if (!with_format) 121 attachments[num_attachments++] = __DRI_BUFFER_FRONT_LEFT; 122 123 for (i = 0; i < *count; i++) { 124 enum pipe_format format; 125 unsigned bind; 126 int att, depth; 127 128 dri_drawable_get_format(drawable, atts[i], &format, &bind); 129 if (format == PIPE_FORMAT_NONE) 130 continue; 131 132 switch (atts[i]) { 133 case ST_ATTACHMENT_FRONT_LEFT: 134 /* already added */ 135 if (!with_format) 136 continue; 137 att = __DRI_BUFFER_FRONT_LEFT; 138 break; 139 case ST_ATTACHMENT_BACK_LEFT: 140 att = __DRI_BUFFER_BACK_LEFT; 141 break; 142 case ST_ATTACHMENT_FRONT_RIGHT: 143 att = __DRI_BUFFER_FRONT_RIGHT; 144 break; 145 case ST_ATTACHMENT_BACK_RIGHT: 146 att = __DRI_BUFFER_BACK_RIGHT; 147 break; 148 default: 149 continue; 150 } 151 152 /* 153 * In this switch statement we must support all formats that 154 * may occur as the stvis->color_format. 155 */ 156 switch(format) { 157 case PIPE_FORMAT_R16G16B16A16_FLOAT: 158 depth = 64; 159 break; 160 case PIPE_FORMAT_R16G16B16X16_FLOAT: 161 depth = 48; 162 break; 163 case PIPE_FORMAT_B10G10R10A2_UNORM: 164 case PIPE_FORMAT_R10G10B10A2_UNORM: 165 case PIPE_FORMAT_BGRA8888_UNORM: 166 case PIPE_FORMAT_RGBA8888_UNORM: 167 depth = 32; 168 break; 169 case PIPE_FORMAT_R10G10B10X2_UNORM: 170 case PIPE_FORMAT_B10G10R10X2_UNORM: 171 depth = 30; 172 break; 173 case PIPE_FORMAT_BGRX8888_UNORM: 174 case PIPE_FORMAT_RGBX8888_UNORM: 175 depth = 24; 176 break; 177 case PIPE_FORMAT_B5G6R5_UNORM: 178 depth = 16; 179 break; 180 default: 181 depth = util_format_get_blocksizebits(format); 182 assert(!"Unexpected format in dri2_drawable_get_buffers()"); 183 } 184 185 attachments[num_attachments++] = att; 186 if (with_format) { 187 attachments[num_attachments++] = depth; 188 } 189 } 190 191 if (with_format) { 192 num_attachments /= 2; 193 buffers = loader->getBuffersWithFormat(dri_drawable, 194 &dri_drawable->w, &dri_drawable->h, 195 attachments, num_attachments, 196 &num_buffers, dri_drawable->loaderPrivate); 197 } 198 else { 199 buffers = loader->getBuffers(dri_drawable, 200 &dri_drawable->w, &dri_drawable->h, 201 attachments, num_attachments, 202 &num_buffers, dri_drawable->loaderPrivate); 203 } 204 205 if (buffers) 206 *count = num_buffers; 207 208 return buffers; 209} 210 211static bool 212dri_image_drawable_get_buffers(struct dri_drawable *drawable, 213 struct __DRIimageList *images, 214 const enum st_attachment_type *statts, 215 unsigned statts_count) 216{ 217 __DRIdrawable *dPriv = drawable->dPriv; 218 __DRIscreen *sPriv = drawable->sPriv; 219 unsigned int image_format = __DRI_IMAGE_FORMAT_NONE; 220 enum pipe_format pf; 221 uint32_t buffer_mask = 0; 222 unsigned i, bind; 223 224 for (i = 0; i < statts_count; i++) { 225 dri_drawable_get_format(drawable, statts[i], &pf, &bind); 226 if (pf == PIPE_FORMAT_NONE) 227 continue; 228 229 switch (statts[i]) { 230 case ST_ATTACHMENT_FRONT_LEFT: 231 buffer_mask |= __DRI_IMAGE_BUFFER_FRONT; 232 break; 233 case ST_ATTACHMENT_BACK_LEFT: 234 buffer_mask |= __DRI_IMAGE_BUFFER_BACK; 235 break; 236 default: 237 continue; 238 } 239 240 switch (pf) { 241 case PIPE_FORMAT_R16G16B16A16_FLOAT: 242 image_format = __DRI_IMAGE_FORMAT_ABGR16161616F; 243 break; 244 case PIPE_FORMAT_R16G16B16X16_FLOAT: 245 image_format = __DRI_IMAGE_FORMAT_XBGR16161616F; 246 break; 247 case PIPE_FORMAT_B5G5R5A1_UNORM: 248 image_format = __DRI_IMAGE_FORMAT_ARGB1555; 249 break; 250 case PIPE_FORMAT_B5G6R5_UNORM: 251 image_format = __DRI_IMAGE_FORMAT_RGB565; 252 break; 253 case PIPE_FORMAT_BGRX8888_UNORM: 254 image_format = __DRI_IMAGE_FORMAT_XRGB8888; 255 break; 256 case PIPE_FORMAT_BGRA8888_UNORM: 257 image_format = __DRI_IMAGE_FORMAT_ARGB8888; 258 break; 259 case PIPE_FORMAT_RGBX8888_UNORM: 260 image_format = __DRI_IMAGE_FORMAT_XBGR8888; 261 break; 262 case PIPE_FORMAT_RGBA8888_UNORM: 263 image_format = __DRI_IMAGE_FORMAT_ABGR8888; 264 break; 265 case PIPE_FORMAT_B10G10R10X2_UNORM: 266 image_format = __DRI_IMAGE_FORMAT_XRGB2101010; 267 break; 268 case PIPE_FORMAT_B10G10R10A2_UNORM: 269 image_format = __DRI_IMAGE_FORMAT_ARGB2101010; 270 break; 271 case PIPE_FORMAT_R10G10B10X2_UNORM: 272 image_format = __DRI_IMAGE_FORMAT_XBGR2101010; 273 break; 274 case PIPE_FORMAT_R10G10B10A2_UNORM: 275 image_format = __DRI_IMAGE_FORMAT_ABGR2101010; 276 break; 277 default: 278 image_format = __DRI_IMAGE_FORMAT_NONE; 279 break; 280 } 281 } 282 283 return (*sPriv->image.loader->getBuffers) (dPriv, image_format, 284 (uint32_t *) &drawable->base.stamp, 285 dPriv->loaderPrivate, buffer_mask, 286 images); 287} 288 289static __DRIbuffer * 290dri2_allocate_buffer(__DRIscreen *sPriv, 291 unsigned attachment, unsigned format, 292 int width, int height) 293{ 294 struct dri_screen *screen = dri_screen(sPriv); 295 struct dri2_buffer *buffer; 296 struct pipe_resource templ; 297 enum pipe_format pf; 298 unsigned bind = 0; 299 struct winsys_handle whandle; 300 301 switch (attachment) { 302 case __DRI_BUFFER_FRONT_LEFT: 303 case __DRI_BUFFER_FAKE_FRONT_LEFT: 304 bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; 305 break; 306 case __DRI_BUFFER_BACK_LEFT: 307 bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; 308 break; 309 case __DRI_BUFFER_DEPTH: 310 case __DRI_BUFFER_DEPTH_STENCIL: 311 case __DRI_BUFFER_STENCIL: 312 bind = PIPE_BIND_DEPTH_STENCIL; /* XXX sampler? */ 313 break; 314 } 315 316 /* because we get the handle and stride */ 317 bind |= PIPE_BIND_SHARED; 318 319 switch (format) { 320 case 64: 321 pf = PIPE_FORMAT_R16G16B16A16_FLOAT; 322 break; 323 case 48: 324 pf = PIPE_FORMAT_R16G16B16X16_FLOAT; 325 break; 326 case 32: 327 pf = PIPE_FORMAT_BGRA8888_UNORM; 328 break; 329 case 30: 330 pf = PIPE_FORMAT_B10G10R10X2_UNORM; 331 break; 332 case 24: 333 pf = PIPE_FORMAT_BGRX8888_UNORM; 334 break; 335 case 16: 336 pf = PIPE_FORMAT_Z16_UNORM; 337 break; 338 default: 339 return NULL; 340 } 341 342 buffer = CALLOC_STRUCT(dri2_buffer); 343 if (!buffer) 344 return NULL; 345 346 memset(&templ, 0, sizeof(templ)); 347 templ.bind = bind; 348 templ.format = pf; 349 templ.target = PIPE_TEXTURE_2D; 350 templ.last_level = 0; 351 templ.width0 = width; 352 templ.height0 = height; 353 templ.depth0 = 1; 354 templ.array_size = 1; 355 356 buffer->resource = 357 screen->base.screen->resource_create(screen->base.screen, &templ); 358 if (!buffer->resource) { 359 FREE(buffer); 360 return NULL; 361 } 362 363 memset(&whandle, 0, sizeof(whandle)); 364 if (screen->can_share_buffer) 365 whandle.type = WINSYS_HANDLE_TYPE_SHARED; 366 else 367 whandle.type = WINSYS_HANDLE_TYPE_KMS; 368 369 screen->base.screen->resource_get_handle(screen->base.screen, NULL, 370 buffer->resource, &whandle, 371 PIPE_HANDLE_USAGE_EXPLICIT_FLUSH); 372 373 buffer->base.attachment = attachment; 374 buffer->base.name = whandle.handle; 375 buffer->base.cpp = util_format_get_blocksize(pf); 376 buffer->base.pitch = whandle.stride; 377 378 return &buffer->base; 379} 380 381static void 382dri2_release_buffer(__DRIscreen *sPriv, __DRIbuffer *bPriv) 383{ 384 struct dri2_buffer *buffer = dri2_buffer(bPriv); 385 386 pipe_resource_reference(&buffer->resource, NULL); 387 FREE(buffer); 388} 389 390/* 391 * Backend functions for st_framebuffer interface. 392 */ 393 394static void 395dri2_allocate_textures(struct dri_context *ctx, 396 struct dri_drawable *drawable, 397 const enum st_attachment_type *statts, 398 unsigned statts_count) 399{ 400 __DRIscreen *sPriv = drawable->sPriv; 401 __DRIdrawable *dri_drawable = drawable->dPriv; 402 struct dri_screen *screen = dri_screen(sPriv); 403 struct pipe_resource templ; 404 boolean alloc_depthstencil = FALSE; 405 unsigned i, j, bind; 406 const __DRIimageLoaderExtension *image = sPriv->image.loader; 407 /* Image specific variables */ 408 struct __DRIimageList images; 409 /* Dri2 specific variables */ 410 __DRIbuffer *buffers = NULL; 411 struct winsys_handle whandle; 412 unsigned num_buffers = statts_count; 413 414 assert(num_buffers <= __DRI_BUFFER_COUNT); 415 416 /* First get the buffers from the loader */ 417 if (image) { 418 if (!dri_image_drawable_get_buffers(drawable, &images, 419 statts, statts_count)) 420 return; 421 } 422 else { 423 buffers = dri2_drawable_get_buffers(drawable, statts, &num_buffers); 424 if (!buffers || (drawable->old_num == num_buffers && 425 drawable->old_w == dri_drawable->w && 426 drawable->old_h == dri_drawable->h && 427 memcmp(drawable->old, buffers, 428 sizeof(__DRIbuffer) * num_buffers) == 0)) 429 return; 430 } 431 432 /* Second clean useless resources*/ 433 434 /* See if we need a depth-stencil buffer. */ 435 for (i = 0; i < statts_count; i++) { 436 if (statts[i] == ST_ATTACHMENT_DEPTH_STENCIL) { 437 alloc_depthstencil = TRUE; 438 break; 439 } 440 } 441 442 /* Delete the resources we won't need. */ 443 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) { 444 /* Don't delete the depth-stencil buffer, we can reuse it. */ 445 if (i == ST_ATTACHMENT_DEPTH_STENCIL && alloc_depthstencil) 446 continue; 447 448 /* Flush the texture before unreferencing, so that other clients can 449 * see what the driver has rendered. 450 */ 451 if (i != ST_ATTACHMENT_DEPTH_STENCIL && drawable->textures[i]) { 452 struct pipe_context *pipe = ctx->st->pipe; 453 pipe->flush_resource(pipe, drawable->textures[i]); 454 } 455 456 pipe_resource_reference(&drawable->textures[i], NULL); 457 } 458 459 if (drawable->stvis.samples > 1) { 460 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) { 461 boolean del = TRUE; 462 463 /* Don't delete MSAA resources for the attachments which are enabled, 464 * we can reuse them. */ 465 for (j = 0; j < statts_count; j++) { 466 if (i == statts[j]) { 467 del = FALSE; 468 break; 469 } 470 } 471 472 if (del) { 473 pipe_resource_reference(&drawable->msaa_textures[i], NULL); 474 } 475 } 476 } 477 478 /* Third use the buffers retrieved to fill the drawable info */ 479 480 memset(&templ, 0, sizeof(templ)); 481 templ.target = screen->target; 482 templ.last_level = 0; 483 templ.depth0 = 1; 484 templ.array_size = 1; 485 486 if (image) { 487 if (images.image_mask & __DRI_IMAGE_BUFFER_FRONT) { 488 struct pipe_resource **buf = 489 &drawable->textures[ST_ATTACHMENT_FRONT_LEFT]; 490 struct pipe_resource *texture = images.front->texture; 491 492 dri_drawable->w = texture->width0; 493 dri_drawable->h = texture->height0; 494 495 pipe_resource_reference(buf, texture); 496 } 497 498 if (images.image_mask & __DRI_IMAGE_BUFFER_BACK) { 499 struct pipe_resource **buf = 500 &drawable->textures[ST_ATTACHMENT_BACK_LEFT]; 501 struct pipe_resource *texture = images.back->texture; 502 503 dri_drawable->w = texture->width0; 504 dri_drawable->h = texture->height0; 505 506 pipe_resource_reference(buf, texture); 507 } 508 509 if (images.image_mask & __DRI_IMAGE_BUFFER_SHARED) { 510 struct pipe_resource **buf = 511 &drawable->textures[ST_ATTACHMENT_BACK_LEFT]; 512 struct pipe_resource *texture = images.back->texture; 513 514 dri_drawable->w = texture->width0; 515 dri_drawable->h = texture->height0; 516 517 pipe_resource_reference(buf, texture); 518 519 ctx->is_shared_buffer_bound = true; 520 } else { 521 ctx->is_shared_buffer_bound = false; 522 } 523 524 /* Note: if there is both a back and a front buffer, 525 * then they have the same size. 526 */ 527 templ.width0 = dri_drawable->w; 528 templ.height0 = dri_drawable->h; 529 } 530 else { 531 memset(&whandle, 0, sizeof(whandle)); 532 533 /* Process DRI-provided buffers and get pipe_resources. */ 534 for (i = 0; i < num_buffers; i++) { 535 __DRIbuffer *buf = &buffers[i]; 536 enum st_attachment_type statt; 537 enum pipe_format format; 538 539 switch (buf->attachment) { 540 case __DRI_BUFFER_FRONT_LEFT: 541 if (!screen->auto_fake_front) { 542 continue; /* invalid attachment */ 543 } 544 FALLTHROUGH; 545 case __DRI_BUFFER_FAKE_FRONT_LEFT: 546 statt = ST_ATTACHMENT_FRONT_LEFT; 547 break; 548 case __DRI_BUFFER_BACK_LEFT: 549 statt = ST_ATTACHMENT_BACK_LEFT; 550 break; 551 default: 552 continue; /* invalid attachment */ 553 } 554 555 dri_drawable_get_format(drawable, statt, &format, &bind); 556 if (format == PIPE_FORMAT_NONE) 557 continue; 558 559 /* dri2_drawable_get_buffers has already filled dri_drawable->w 560 * and dri_drawable->h */ 561 templ.width0 = dri_drawable->w; 562 templ.height0 = dri_drawable->h; 563 templ.format = format; 564 templ.bind = bind; 565 whandle.handle = buf->name; 566 whandle.stride = buf->pitch; 567 whandle.offset = 0; 568 whandle.format = format; 569 whandle.modifier = DRM_FORMAT_MOD_INVALID; 570 if (screen->can_share_buffer) 571 whandle.type = WINSYS_HANDLE_TYPE_SHARED; 572 else 573 whandle.type = WINSYS_HANDLE_TYPE_KMS; 574 drawable->textures[statt] = 575 screen->base.screen->resource_from_handle(screen->base.screen, 576 &templ, &whandle, 577 PIPE_HANDLE_USAGE_EXPLICIT_FLUSH); 578 assert(drawable->textures[statt]); 579 } 580 } 581 582 /* Allocate private MSAA colorbuffers. */ 583 if (drawable->stvis.samples > 1) { 584 for (i = 0; i < statts_count; i++) { 585 enum st_attachment_type statt = statts[i]; 586 587 if (statt == ST_ATTACHMENT_DEPTH_STENCIL) 588 continue; 589 590 if (drawable->textures[statt]) { 591 templ.format = drawable->textures[statt]->format; 592 templ.bind = drawable->textures[statt]->bind & 593 ~(PIPE_BIND_SCANOUT | PIPE_BIND_SHARED); 594 templ.nr_samples = drawable->stvis.samples; 595 templ.nr_storage_samples = drawable->stvis.samples; 596 597 /* Try to reuse the resource. 598 * (the other resource parameters should be constant) 599 */ 600 if (!drawable->msaa_textures[statt] || 601 drawable->msaa_textures[statt]->width0 != templ.width0 || 602 drawable->msaa_textures[statt]->height0 != templ.height0) { 603 /* Allocate a new one. */ 604 pipe_resource_reference(&drawable->msaa_textures[statt], NULL); 605 606 drawable->msaa_textures[statt] = 607 screen->base.screen->resource_create(screen->base.screen, 608 &templ); 609 assert(drawable->msaa_textures[statt]); 610 611 /* If there are any MSAA resources, we should initialize them 612 * such that they contain the same data as the single-sample 613 * resources we just got from the X server. 614 * 615 * The reason for this is that the gallium frontend (and 616 * therefore the app) can access the MSAA resources only. 617 * The single-sample resources are not exposed 618 * to the gallium frontend. 619 * 620 */ 621 dri_pipe_blit(ctx->st->pipe, 622 drawable->msaa_textures[statt], 623 drawable->textures[statt]); 624 } 625 } 626 else { 627 pipe_resource_reference(&drawable->msaa_textures[statt], NULL); 628 } 629 } 630 } 631 632 /* Allocate a private depth-stencil buffer. */ 633 if (alloc_depthstencil) { 634 enum st_attachment_type statt = ST_ATTACHMENT_DEPTH_STENCIL; 635 struct pipe_resource **zsbuf; 636 enum pipe_format format; 637 unsigned bind; 638 639 dri_drawable_get_format(drawable, statt, &format, &bind); 640 641 if (format) { 642 templ.format = format; 643 templ.bind = bind & ~PIPE_BIND_SHARED; 644 645 if (drawable->stvis.samples > 1) { 646 templ.nr_samples = drawable->stvis.samples; 647 templ.nr_storage_samples = drawable->stvis.samples; 648 zsbuf = &drawable->msaa_textures[statt]; 649 } 650 else { 651 templ.nr_samples = 0; 652 templ.nr_storage_samples = 0; 653 zsbuf = &drawable->textures[statt]; 654 } 655 656 /* Try to reuse the resource. 657 * (the other resource parameters should be constant) 658 */ 659 if (!*zsbuf || 660 (*zsbuf)->width0 != templ.width0 || 661 (*zsbuf)->height0 != templ.height0) { 662 /* Allocate a new one. */ 663 pipe_resource_reference(zsbuf, NULL); 664 *zsbuf = screen->base.screen->resource_create(screen->base.screen, 665 &templ); 666 assert(*zsbuf); 667 } 668 } 669 else { 670 pipe_resource_reference(&drawable->msaa_textures[statt], NULL); 671 pipe_resource_reference(&drawable->textures[statt], NULL); 672 } 673 } 674 675 /* For DRI2, we may get the same buffers again from the server. 676 * To prevent useless imports of gem names, drawable->old* is used 677 * to bypass the import if we get the same buffers. This doesn't apply 678 * to DRI3/Wayland, users of image.loader, since the buffer is managed 679 * by the client (no import), and the back buffer is going to change 680 * at every redraw. 681 */ 682 if (!image) { 683 drawable->old_num = num_buffers; 684 drawable->old_w = dri_drawable->w; 685 drawable->old_h = dri_drawable->h; 686 memcpy(drawable->old, buffers, sizeof(__DRIbuffer) * num_buffers); 687 } 688} 689 690static bool 691dri2_flush_frontbuffer(struct dri_context *ctx, 692 struct dri_drawable *drawable, 693 enum st_attachment_type statt) 694{ 695 __DRIdrawable *dri_drawable = drawable->dPriv; 696 const __DRIimageLoaderExtension *image = drawable->sPriv->image.loader; 697 const __DRIdri2LoaderExtension *loader = drawable->sPriv->dri2.loader; 698 const __DRImutableRenderBufferLoaderExtension *shared_buffer_loader = 699 drawable->sPriv->mutableRenderBuffer.loader; 700 struct pipe_context *pipe = ctx->st->pipe; 701 struct pipe_fence_handle *fence = NULL; 702 int fence_fd = -1; 703 704 /* We need to flush for front buffer rendering when either we're using the 705 * front buffer at the GL API level, or when EGL_KHR_mutable_render_buffer 706 * has redirected GL_BACK to the front buffer. 707 */ 708 if (statt != ST_ATTACHMENT_FRONT_LEFT && 709 (!ctx->is_shared_buffer_bound || statt != ST_ATTACHMENT_BACK_LEFT)) 710 return false; 711 712 if (drawable->stvis.samples > 1) { 713 /* Resolve the buffer used for front rendering. */ 714 dri_pipe_blit(ctx->st->pipe, drawable->textures[statt], 715 drawable->msaa_textures[statt]); 716 } 717 718 if (drawable->textures[statt]) { 719 pipe->flush_resource(pipe, drawable->textures[statt]); 720 } 721 722 if (ctx->is_shared_buffer_bound) { 723 /* is_shared_buffer_bound should only be true with image extension: */ 724 assert(image); 725 pipe->flush(pipe, &fence, PIPE_FLUSH_FENCE_FD); 726 } else { 727 pipe->flush(pipe, NULL, 0); 728 } 729 730 if (image) { 731 image->flushFrontBuffer(dri_drawable, dri_drawable->loaderPrivate); 732 if (ctx->is_shared_buffer_bound) { 733 if (fence) 734 fence_fd = pipe->screen->fence_get_fd(pipe->screen, fence); 735 736 shared_buffer_loader->displaySharedBuffer(dri_drawable, fence_fd, 737 dri_drawable->loaderPrivate); 738 739 pipe->screen->fence_reference(pipe->screen, &fence, NULL); 740 } 741 } 742 else if (loader->flushFrontBuffer) { 743 loader->flushFrontBuffer(dri_drawable, dri_drawable->loaderPrivate); 744 } 745 746 return true; 747} 748 749/** 750 * The struct dri_drawable flush_swapbuffers callback 751 */ 752static void 753dri2_flush_swapbuffers(struct dri_context *ctx, 754 struct dri_drawable *drawable) 755{ 756 __DRIdrawable *dri_drawable = drawable->dPriv; 757 const __DRIimageLoaderExtension *image = drawable->sPriv->image.loader; 758 759 if (image && image->base.version >= 3 && image->flushSwapBuffers) { 760 image->flushSwapBuffers(dri_drawable, dri_drawable->loaderPrivate); 761 } 762} 763 764static void 765dri2_update_tex_buffer(struct dri_drawable *drawable, 766 struct dri_context *ctx, 767 struct pipe_resource *res) 768{ 769 /* no-op */ 770} 771 772static const struct dri2_format_mapping r8_g8b8_mapping = { 773 DRM_FORMAT_NV12, 774 __DRI_IMAGE_FORMAT_NONE, 775 __DRI_IMAGE_COMPONENTS_Y_UV, 776 PIPE_FORMAT_R8_G8B8_420_UNORM, 777 2, 778 { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8 }, 779 { 1, 1, 1, __DRI_IMAGE_FORMAT_GR88 } } 780}; 781 782static const struct dri2_format_mapping r8g8_r8b8_mapping = { 783 DRM_FORMAT_YUYV, 784 __DRI_IMAGE_FORMAT_NONE, 785 __DRI_IMAGE_COMPONENTS_Y_XUXV, 786 PIPE_FORMAT_R8G8_R8B8_UNORM, 2, 787 { { 0, 0, 0, __DRI_IMAGE_FORMAT_GR88 }, 788 { 0, 1, 0, __DRI_IMAGE_FORMAT_ARGB8888 } } 789}; 790 791static const struct dri2_format_mapping g8r8_b8r8_mapping = { 792 DRM_FORMAT_UYVY, 793 __DRI_IMAGE_FORMAT_NONE, 794 __DRI_IMAGE_COMPONENTS_Y_XUXV, 795 PIPE_FORMAT_G8R8_B8R8_UNORM, 2, 796 { { 0, 0, 0, __DRI_IMAGE_FORMAT_GR88 }, 797 { 0, 1, 0, __DRI_IMAGE_FORMAT_ABGR8888 } } 798}; 799 800static __DRIimage * 801dri2_create_image_from_winsys(__DRIscreen *_screen, 802 int width, int height, const struct dri2_format_mapping *map, 803 int num_handles, struct winsys_handle *whandle, 804 bool is_protected_content, 805 void *loaderPrivate) 806{ 807 struct dri_screen *screen = dri_screen(_screen); 808 struct pipe_screen *pscreen = screen->base.screen; 809 __DRIimage *img; 810 struct pipe_resource templ; 811 unsigned tex_usage = 0; 812 int i; 813 bool use_lowered = false; 814 const unsigned format_planes = util_format_get_num_planes(map->pipe_format); 815 816 if (pscreen->is_format_supported(pscreen, map->pipe_format, screen->target, 0, 0, 817 PIPE_BIND_RENDER_TARGET)) 818 tex_usage |= PIPE_BIND_RENDER_TARGET; 819 if (pscreen->is_format_supported(pscreen, map->pipe_format, screen->target, 0, 0, 820 PIPE_BIND_SAMPLER_VIEW)) 821 tex_usage |= PIPE_BIND_SAMPLER_VIEW; 822 823 /* For NV12, see if we have support for sampling r8_b8g8 */ 824 if (!tex_usage && map->pipe_format == PIPE_FORMAT_NV12 && 825 pscreen->is_format_supported(pscreen, PIPE_FORMAT_R8_G8B8_420_UNORM, 826 screen->target, 0, 0, PIPE_BIND_SAMPLER_VIEW)) { 827 map = &r8_g8b8_mapping; 828 tex_usage |= PIPE_BIND_SAMPLER_VIEW; 829 } 830 831 /* If the hardware supports R8G8_R8B8 style subsampled RGB formats, these 832 * can be used for YUYV and UYVY formats. 833 */ 834 if (!tex_usage && map->pipe_format == PIPE_FORMAT_YUYV && 835 pscreen->is_format_supported(pscreen, PIPE_FORMAT_R8G8_R8B8_UNORM, 836 screen->target, 0, 0, PIPE_BIND_SAMPLER_VIEW)) { 837 map = &r8g8_r8b8_mapping; 838 tex_usage |= PIPE_BIND_SAMPLER_VIEW; 839 } 840 841 if (!tex_usage && map->pipe_format == PIPE_FORMAT_UYVY && 842 pscreen->is_format_supported(pscreen, PIPE_FORMAT_G8R8_B8R8_UNORM, 843 screen->target, 0, 0, PIPE_BIND_SAMPLER_VIEW)) { 844 map = &g8r8_b8r8_mapping; 845 tex_usage |= PIPE_BIND_SAMPLER_VIEW; 846 } 847 848 if (!tex_usage && util_format_is_yuv(map->pipe_format)) { 849 /* YUV format sampling can be emulated by the GL gallium frontend by 850 * using multiple samplers of varying formats. 851 * If no tex_usage is set and we detect a YUV format, 852 * test for support of all planes' sampler formats and 853 * add sampler view usage. 854 */ 855 use_lowered = true; 856 if (dri2_yuv_dma_buf_supported(screen, map)) 857 tex_usage |= PIPE_BIND_SAMPLER_VIEW; 858 } 859 860 if (!tex_usage) 861 return NULL; 862 863 if (is_protected_content) 864 tex_usage |= PIPE_BIND_PROTECTED; 865 866 img = CALLOC_STRUCT(__DRIimageRec); 867 if (!img) 868 return NULL; 869 870 memset(&templ, 0, sizeof(templ)); 871 templ.bind = tex_usage; 872 templ.target = screen->target; 873 templ.last_level = 0; 874 templ.depth0 = 1; 875 templ.array_size = 1; 876 877 for (i = num_handles - 1; i >= format_planes; i--) { 878 struct pipe_resource *tex; 879 880 templ.next = img->texture; 881 882 tex = pscreen->resource_from_handle(pscreen, &templ, &whandle[i], 883 PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE); 884 if (!tex) { 885 pipe_resource_reference(&img->texture, NULL); 886 FREE(img); 887 return NULL; 888 } 889 890 img->texture = tex; 891 } 892 893 for (i = (use_lowered ? map->nplanes : format_planes) - 1; i >= 0; i--) { 894 struct pipe_resource *tex; 895 896 templ.next = img->texture; 897 templ.width0 = width >> map->planes[i].width_shift; 898 templ.height0 = height >> map->planes[i].height_shift; 899 if (use_lowered) 900 templ.format = dri2_get_pipe_format_for_dri_format(map->planes[i].dri_format); 901 else 902 templ.format = map->pipe_format; 903 assert(templ.format != PIPE_FORMAT_NONE); 904 905 tex = pscreen->resource_from_handle(pscreen, 906 &templ, &whandle[use_lowered ? map->planes[i].buffer_index : i], 907 PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE); 908 if (!tex) { 909 pipe_resource_reference(&img->texture, NULL); 910 FREE(img); 911 return NULL; 912 } 913 914 /* Reject image creation if there's an inconsistency between 915 * content protection status of tex and img. 916 */ 917 const struct driOptionCache *optionCache = &screen->dev->option_cache; 918 if (!driQueryOptionb(optionCache, "disable_protected_content_check") && 919 (bool)(tex->bind & PIPE_BIND_PROTECTED) != is_protected_content) { 920 pipe_resource_reference(&img->texture, NULL); 921 pipe_resource_reference(&tex, NULL); 922 FREE(img); 923 return NULL; 924 } 925 926 img->texture = tex; 927 } 928 929 img->level = 0; 930 img->layer = 0; 931 img->use = 0; 932 img->loader_private = loaderPrivate; 933 img->sPriv = _screen; 934 935 return img; 936} 937 938static __DRIimage * 939dri2_create_image_from_name(__DRIscreen *_screen, 940 int width, int height, int format, 941 int name, int pitch, void *loaderPrivate) 942{ 943 const struct dri2_format_mapping *map = dri2_get_mapping_by_format(format); 944 struct winsys_handle whandle; 945 __DRIimage *img; 946 947 if (!map) 948 return NULL; 949 950 memset(&whandle, 0, sizeof(whandle)); 951 whandle.type = WINSYS_HANDLE_TYPE_SHARED; 952 whandle.handle = name; 953 whandle.format = map->pipe_format; 954 whandle.modifier = DRM_FORMAT_MOD_INVALID; 955 956 whandle.stride = pitch * util_format_get_blocksize(map->pipe_format); 957 958 img = dri2_create_image_from_winsys(_screen, width, height, map, 959 1, &whandle, false, loaderPrivate); 960 961 if (!img) 962 return NULL; 963 964 img->dri_components = map->dri_components; 965 img->dri_fourcc = map->dri_fourcc; 966 img->dri_format = map->dri_format; 967 968 return img; 969} 970 971static unsigned 972dri2_get_modifier_num_planes(__DRIscreen *_screen, 973 uint64_t modifier, int fourcc) 974{ 975 struct pipe_screen *pscreen = dri_screen(_screen)->base.screen; 976 const struct dri2_format_mapping *map = dri2_get_mapping_by_fourcc(fourcc); 977 978 if (!map) 979 return 0; 980 981 switch (modifier) { 982 case DRM_FORMAT_MOD_LINEAR: 983 /* DRM_FORMAT_MOD_NONE is the same as LINEAR */ 984 case DRM_FORMAT_MOD_INVALID: 985 return util_format_get_num_planes(map->pipe_format); 986 default: 987 if (!pscreen->is_dmabuf_modifier_supported || 988 !pscreen->is_dmabuf_modifier_supported(pscreen, modifier, 989 map->pipe_format, NULL)) { 990 return 0; 991 } 992 993 if (pscreen->get_dmabuf_modifier_planes) { 994 return pscreen->get_dmabuf_modifier_planes(pscreen, modifier, 995 map->pipe_format); 996 } 997 998 return map->nplanes; 999 } 1000} 1001 1002static __DRIimage * 1003dri2_create_image_from_fd(__DRIscreen *_screen, 1004 int width, int height, int fourcc, 1005 uint64_t modifier, int *fds, int num_fds, 1006 int *strides, int *offsets, bool protected_content, 1007 unsigned *error, void *loaderPrivate) 1008{ 1009 struct winsys_handle whandles[4]; 1010 const struct dri2_format_mapping *map = dri2_get_mapping_by_fourcc(fourcc); 1011 __DRIimage *img = NULL; 1012 unsigned err = __DRI_IMAGE_ERROR_SUCCESS; 1013 int i; 1014 const int expected_num_fds = dri2_get_modifier_num_planes(_screen, modifier, fourcc); 1015 1016 if (!map || expected_num_fds == 0) { 1017 err = __DRI_IMAGE_ERROR_BAD_MATCH; 1018 goto exit; 1019 } 1020 1021 if (num_fds != expected_num_fds) { 1022 err = __DRI_IMAGE_ERROR_BAD_MATCH; 1023 goto exit; 1024 } 1025 1026 memset(whandles, 0, sizeof(whandles)); 1027 1028 for (i = 0; i < num_fds; i++) { 1029 if (fds[i] < 0) { 1030 err = __DRI_IMAGE_ERROR_BAD_ALLOC; 1031 goto exit; 1032 } 1033 1034 whandles[i].type = WINSYS_HANDLE_TYPE_FD; 1035 whandles[i].handle = (unsigned)fds[i]; 1036 whandles[i].stride = (unsigned)strides[i]; 1037 whandles[i].offset = (unsigned)offsets[i]; 1038 whandles[i].format = map->pipe_format; 1039 whandles[i].modifier = modifier; 1040 whandles[i].plane = i; 1041 } 1042 1043 img = dri2_create_image_from_winsys(_screen, width, height, map, 1044 num_fds, whandles, protected_content, 1045 loaderPrivate); 1046 if(img == NULL) { 1047 err = __DRI_IMAGE_ERROR_BAD_ALLOC; 1048 goto exit; 1049 } 1050 1051 img->dri_components = map->dri_components; 1052 img->dri_fourcc = fourcc; 1053 img->dri_format = map->dri_format; 1054 img->imported_dmabuf = TRUE; 1055 1056exit: 1057 if (error) 1058 *error = err; 1059 1060 return img; 1061} 1062 1063static __DRIimage * 1064dri2_create_image_common(__DRIscreen *_screen, 1065 int width, int height, 1066 int format, unsigned int use, 1067 const uint64_t *modifiers, 1068 const unsigned count, 1069 void *loaderPrivate) 1070{ 1071 const struct dri2_format_mapping *map = dri2_get_mapping_by_format(format); 1072 struct dri_screen *screen = dri_screen(_screen); 1073 struct pipe_screen *pscreen = screen->base.screen; 1074 __DRIimage *img; 1075 struct pipe_resource templ; 1076 unsigned tex_usage = 0; 1077 1078 if (!map) 1079 return NULL; 1080 1081 if (pscreen->is_format_supported(pscreen, map->pipe_format, screen->target, 1082 0, 0, PIPE_BIND_RENDER_TARGET)) 1083 tex_usage |= PIPE_BIND_RENDER_TARGET; 1084 if (pscreen->is_format_supported(pscreen, map->pipe_format, screen->target, 1085 0, 0, PIPE_BIND_SAMPLER_VIEW)) 1086 tex_usage |= PIPE_BIND_SAMPLER_VIEW; 1087 1088 if (!tex_usage) 1089 return NULL; 1090 1091 if (use & __DRI_IMAGE_USE_SCANOUT) 1092 tex_usage |= PIPE_BIND_SCANOUT; 1093 if (use & __DRI_IMAGE_USE_SHARE) 1094 tex_usage |= PIPE_BIND_SHARED; 1095 if (use & __DRI_IMAGE_USE_LINEAR) 1096 tex_usage |= PIPE_BIND_LINEAR; 1097 if (use & __DRI_IMAGE_USE_CURSOR) { 1098 if (width != 64 || height != 64) 1099 return NULL; 1100 tex_usage |= PIPE_BIND_CURSOR; 1101 } 1102 if (use & __DRI_IMAGE_USE_PROTECTED) 1103 tex_usage |= PIPE_BIND_PROTECTED; 1104 1105 img = CALLOC_STRUCT(__DRIimageRec); 1106 if (!img) 1107 return NULL; 1108 1109 memset(&templ, 0, sizeof(templ)); 1110 templ.bind = tex_usage; 1111 templ.format = map->pipe_format; 1112 templ.target = PIPE_TEXTURE_2D; 1113 templ.last_level = 0; 1114 templ.width0 = width; 1115 templ.height0 = height; 1116 templ.depth0 = 1; 1117 templ.array_size = 1; 1118 1119 if (modifiers) 1120 img->texture = 1121 screen->base.screen 1122 ->resource_create_with_modifiers(screen->base.screen, 1123 &templ, 1124 modifiers, 1125 count); 1126 else 1127 img->texture = 1128 screen->base.screen->resource_create(screen->base.screen, &templ); 1129 if (!img->texture) { 1130 FREE(img); 1131 return NULL; 1132 } 1133 1134 img->level = 0; 1135 img->layer = 0; 1136 img->dri_format = format; 1137 img->dri_fourcc = map->dri_fourcc; 1138 img->dri_components = 0; 1139 img->use = use; 1140 1141 img->loader_private = loaderPrivate; 1142 img->sPriv = _screen; 1143 return img; 1144} 1145 1146static __DRIimage * 1147dri2_create_image(__DRIscreen *_screen, 1148 int width, int height, int format, 1149 unsigned int use, void *loaderPrivate) 1150{ 1151 return dri2_create_image_common(_screen, width, height, format, use, 1152 NULL /* modifiers */, 0 /* count */, 1153 loaderPrivate); 1154} 1155 1156static __DRIimage * 1157dri2_create_image_with_modifiers(__DRIscreen *dri_screen, 1158 int width, int height, int format, 1159 const uint64_t *modifiers, 1160 const unsigned count, 1161 void *loaderPrivate) 1162{ 1163 return dri2_create_image_common(dri_screen, width, height, format, 1164 __DRI_IMAGE_USE_SHARE, modifiers, count, 1165 loaderPrivate); 1166} 1167 1168static __DRIimage * 1169dri2_create_image_with_modifiers2(__DRIscreen *dri_screen, 1170 int width, int height, int format, 1171 const uint64_t *modifiers, 1172 const unsigned count, unsigned int use, 1173 void *loaderPrivate) 1174{ 1175 return dri2_create_image_common(dri_screen, width, height, format, use, 1176 modifiers, count, loaderPrivate); 1177} 1178 1179static bool 1180dri2_query_image_common(__DRIimage *image, int attrib, int *value) 1181{ 1182 switch (attrib) { 1183 case __DRI_IMAGE_ATTRIB_FORMAT: 1184 *value = image->dri_format; 1185 return true; 1186 case __DRI_IMAGE_ATTRIB_WIDTH: 1187 *value = image->texture->width0; 1188 return true; 1189 case __DRI_IMAGE_ATTRIB_HEIGHT: 1190 *value = image->texture->height0; 1191 return true; 1192 case __DRI_IMAGE_ATTRIB_COMPONENTS: 1193 if (image->dri_components == 0) 1194 return false; 1195 *value = image->dri_components; 1196 return true; 1197 case __DRI_IMAGE_ATTRIB_FOURCC: 1198 if (image->dri_fourcc) { 1199 *value = image->dri_fourcc; 1200 } else { 1201 const struct dri2_format_mapping *map; 1202 1203 map = dri2_get_mapping_by_format(image->dri_format); 1204 if (!map) 1205 return false; 1206 1207 *value = map->dri_fourcc; 1208 } 1209 return true; 1210 default: 1211 return false; 1212 } 1213} 1214 1215static bool 1216dri2_query_image_by_resource_handle(__DRIimage *image, int attrib, int *value) 1217{ 1218 struct pipe_screen *pscreen = image->texture->screen; 1219 struct winsys_handle whandle; 1220 struct pipe_resource *tex; 1221 unsigned usage; 1222 memset(&whandle, 0, sizeof(whandle)); 1223 whandle.plane = image->plane; 1224 int i; 1225 1226 switch (attrib) { 1227 case __DRI_IMAGE_ATTRIB_STRIDE: 1228 case __DRI_IMAGE_ATTRIB_OFFSET: 1229 case __DRI_IMAGE_ATTRIB_HANDLE: 1230 whandle.type = WINSYS_HANDLE_TYPE_KMS; 1231 break; 1232 case __DRI_IMAGE_ATTRIB_NAME: 1233 whandle.type = WINSYS_HANDLE_TYPE_SHARED; 1234 break; 1235 case __DRI_IMAGE_ATTRIB_FD: 1236 whandle.type = WINSYS_HANDLE_TYPE_FD; 1237 break; 1238 case __DRI_IMAGE_ATTRIB_NUM_PLANES: 1239 for (i = 0, tex = image->texture; tex; tex = tex->next) 1240 i++; 1241 *value = i; 1242 return true; 1243 case __DRI_IMAGE_ATTRIB_MODIFIER_UPPER: 1244 case __DRI_IMAGE_ATTRIB_MODIFIER_LOWER: 1245 whandle.type = WINSYS_HANDLE_TYPE_KMS; 1246 whandle.modifier = DRM_FORMAT_MOD_INVALID; 1247 break; 1248 default: 1249 return false; 1250 } 1251 1252 usage = PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE; 1253 1254 if (image->use & __DRI_IMAGE_USE_BACKBUFFER) 1255 usage |= PIPE_HANDLE_USAGE_EXPLICIT_FLUSH; 1256 1257 if (!pscreen->resource_get_handle(pscreen, NULL, image->texture, 1258 &whandle, usage)) 1259 return false; 1260 1261 switch (attrib) { 1262 case __DRI_IMAGE_ATTRIB_STRIDE: 1263 *value = whandle.stride; 1264 return true; 1265 case __DRI_IMAGE_ATTRIB_OFFSET: 1266 *value = whandle.offset; 1267 return true; 1268 case __DRI_IMAGE_ATTRIB_HANDLE: 1269 case __DRI_IMAGE_ATTRIB_NAME: 1270 case __DRI_IMAGE_ATTRIB_FD: 1271 *value = whandle.handle; 1272 return true; 1273 case __DRI_IMAGE_ATTRIB_MODIFIER_UPPER: 1274 if (whandle.modifier == DRM_FORMAT_MOD_INVALID) 1275 return false; 1276 *value = (whandle.modifier >> 32) & 0xffffffff; 1277 return true; 1278 case __DRI_IMAGE_ATTRIB_MODIFIER_LOWER: 1279 if (whandle.modifier == DRM_FORMAT_MOD_INVALID) 1280 return false; 1281 *value = whandle.modifier & 0xffffffff; 1282 return true; 1283 default: 1284 return false; 1285 } 1286} 1287 1288static bool 1289dri2_resource_get_param(__DRIimage *image, enum pipe_resource_param param, 1290 unsigned handle_usage, uint64_t *value) 1291{ 1292 struct pipe_screen *pscreen = image->texture->screen; 1293 if (!pscreen->resource_get_param) 1294 return false; 1295 1296 if (image->use & __DRI_IMAGE_USE_BACKBUFFER) 1297 handle_usage |= PIPE_HANDLE_USAGE_EXPLICIT_FLUSH; 1298 1299 return pscreen->resource_get_param(pscreen, NULL, image->texture, 1300 image->plane, 0, 0, param, handle_usage, 1301 value); 1302} 1303 1304static bool 1305dri2_query_image_by_resource_param(__DRIimage *image, int attrib, int *value) 1306{ 1307 enum pipe_resource_param param; 1308 uint64_t res_param; 1309 unsigned handle_usage; 1310 1311 if (!image->texture->screen->resource_get_param) 1312 return false; 1313 1314 switch (attrib) { 1315 case __DRI_IMAGE_ATTRIB_STRIDE: 1316 param = PIPE_RESOURCE_PARAM_STRIDE; 1317 break; 1318 case __DRI_IMAGE_ATTRIB_OFFSET: 1319 param = PIPE_RESOURCE_PARAM_OFFSET; 1320 break; 1321 case __DRI_IMAGE_ATTRIB_NUM_PLANES: 1322 param = PIPE_RESOURCE_PARAM_NPLANES; 1323 break; 1324 case __DRI_IMAGE_ATTRIB_MODIFIER_UPPER: 1325 case __DRI_IMAGE_ATTRIB_MODIFIER_LOWER: 1326 param = PIPE_RESOURCE_PARAM_MODIFIER; 1327 break; 1328 case __DRI_IMAGE_ATTRIB_HANDLE: 1329 param = PIPE_RESOURCE_PARAM_HANDLE_TYPE_KMS; 1330 break; 1331 case __DRI_IMAGE_ATTRIB_NAME: 1332 param = PIPE_RESOURCE_PARAM_HANDLE_TYPE_SHARED; 1333 break; 1334 case __DRI_IMAGE_ATTRIB_FD: 1335 param = PIPE_RESOURCE_PARAM_HANDLE_TYPE_FD; 1336 break; 1337 default: 1338 return false; 1339 } 1340 1341 handle_usage = PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE; 1342 1343 if (!dri2_resource_get_param(image, param, handle_usage, &res_param)) 1344 return false; 1345 1346 switch (attrib) { 1347 case __DRI_IMAGE_ATTRIB_STRIDE: 1348 case __DRI_IMAGE_ATTRIB_OFFSET: 1349 case __DRI_IMAGE_ATTRIB_NUM_PLANES: 1350 if (res_param > INT_MAX) 1351 return false; 1352 *value = (int)res_param; 1353 return true; 1354 case __DRI_IMAGE_ATTRIB_HANDLE: 1355 case __DRI_IMAGE_ATTRIB_NAME: 1356 case __DRI_IMAGE_ATTRIB_FD: 1357 if (res_param > UINT_MAX) 1358 return false; 1359 *value = (int)res_param; 1360 return true; 1361 case __DRI_IMAGE_ATTRIB_MODIFIER_UPPER: 1362 if (res_param == DRM_FORMAT_MOD_INVALID) 1363 return false; 1364 *value = (res_param >> 32) & 0xffffffff; 1365 return true; 1366 case __DRI_IMAGE_ATTRIB_MODIFIER_LOWER: 1367 if (res_param == DRM_FORMAT_MOD_INVALID) 1368 return false; 1369 *value = res_param & 0xffffffff; 1370 return true; 1371 default: 1372 return false; 1373 } 1374} 1375 1376static GLboolean 1377dri2_query_image(__DRIimage *image, int attrib, int *value) 1378{ 1379 if (dri2_query_image_common(image, attrib, value)) 1380 return GL_TRUE; 1381 else if (dri2_query_image_by_resource_param(image, attrib, value)) 1382 return GL_TRUE; 1383 else if (dri2_query_image_by_resource_handle(image, attrib, value)) 1384 return GL_TRUE; 1385 else 1386 return GL_FALSE; 1387} 1388 1389static __DRIimage * 1390dri2_dup_image(__DRIimage *image, void *loaderPrivate) 1391{ 1392 __DRIimage *img; 1393 1394 img = CALLOC_STRUCT(__DRIimageRec); 1395 if (!img) 1396 return NULL; 1397 1398 img->texture = NULL; 1399 pipe_resource_reference(&img->texture, image->texture); 1400 img->level = image->level; 1401 img->layer = image->layer; 1402 img->dri_format = image->dri_format; 1403 /* This should be 0 for sub images, but dup is also used for base images. */ 1404 img->dri_components = image->dri_components; 1405 img->use = image->use; 1406 img->loader_private = loaderPrivate; 1407 img->sPriv = image->sPriv; 1408 1409 return img; 1410} 1411 1412static GLboolean 1413dri2_validate_usage(__DRIimage *image, unsigned int use) 1414{ 1415 if (!image || !image->texture) 1416 return false; 1417 1418 struct pipe_screen *screen = image->texture->screen; 1419 if (!screen->check_resource_capability) 1420 return true; 1421 1422 /* We don't want to check these: 1423 * __DRI_IMAGE_USE_SHARE (all images are shareable) 1424 * __DRI_IMAGE_USE_BACKBUFFER (all images support this) 1425 */ 1426 unsigned bind = 0; 1427 if (use & __DRI_IMAGE_USE_SCANOUT) 1428 bind |= PIPE_BIND_SCANOUT; 1429 if (use & __DRI_IMAGE_USE_LINEAR) 1430 bind |= PIPE_BIND_LINEAR; 1431 if (use & __DRI_IMAGE_USE_CURSOR) 1432 bind |= PIPE_BIND_CURSOR; 1433 1434 if (!bind) 1435 return true; 1436 1437 return screen->check_resource_capability(screen, image->texture, bind); 1438} 1439 1440static __DRIimage * 1441dri2_from_names(__DRIscreen *screen, int width, int height, int format, 1442 int *names, int num_names, int *strides, int *offsets, 1443 void *loaderPrivate) 1444{ 1445 const struct dri2_format_mapping *map = dri2_get_mapping_by_format(format); 1446 __DRIimage *img; 1447 struct winsys_handle whandle; 1448 1449 if (!map) 1450 return NULL; 1451 1452 if (num_names != 1) 1453 return NULL; 1454 1455 memset(&whandle, 0, sizeof(whandle)); 1456 whandle.type = WINSYS_HANDLE_TYPE_SHARED; 1457 whandle.handle = names[0]; 1458 whandle.stride = strides[0]; 1459 whandle.offset = offsets[0]; 1460 whandle.format = map->pipe_format; 1461 whandle.modifier = DRM_FORMAT_MOD_INVALID; 1462 1463 img = dri2_create_image_from_winsys(screen, width, height, map, 1464 1, &whandle, false, loaderPrivate); 1465 if (img == NULL) 1466 return NULL; 1467 1468 img->dri_components = map->dri_components; 1469 img->dri_fourcc = map->dri_fourcc; 1470 img->dri_format = map->pipe_format; 1471 1472 return img; 1473} 1474 1475static __DRIimage * 1476dri2_from_planar(__DRIimage *image, int plane, void *loaderPrivate) 1477{ 1478 __DRIimage *img; 1479 1480 if (plane < 0) { 1481 return NULL; 1482 } else if (plane > 0) { 1483 uint64_t planes; 1484 if (!dri2_resource_get_param(image, PIPE_RESOURCE_PARAM_NPLANES, 0, 1485 &planes) || 1486 plane >= planes) { 1487 return NULL; 1488 } 1489 } 1490 1491 if (image->dri_components == 0) { 1492 uint64_t modifier; 1493 if (!dri2_resource_get_param(image, PIPE_RESOURCE_PARAM_MODIFIER, 0, 1494 &modifier) || 1495 modifier == DRM_FORMAT_MOD_INVALID) { 1496 return NULL; 1497 } 1498 } 1499 1500 img = dri2_dup_image(image, loaderPrivate); 1501 if (img == NULL) 1502 return NULL; 1503 1504 if (img->texture->screen->resource_changed) 1505 img->texture->screen->resource_changed(img->texture->screen, 1506 img->texture); 1507 1508 /* set this to 0 for sub images. */ 1509 img->dri_components = 0; 1510 img->plane = plane; 1511 return img; 1512} 1513 1514static __DRIimage * 1515dri2_from_fds(__DRIscreen *screen, int width, int height, int fourcc, 1516 int *fds, int num_fds, int *strides, int *offsets, 1517 void *loaderPrivate) 1518{ 1519 return dri2_create_image_from_fd(screen, width, height, fourcc, 1520 DRM_FORMAT_MOD_INVALID, fds, num_fds, 1521 strides, offsets, false, NULL, loaderPrivate); 1522} 1523 1524static boolean 1525dri2_query_dma_buf_modifiers(__DRIscreen *_screen, int fourcc, int max, 1526 uint64_t *modifiers, unsigned int *external_only, 1527 int *count) 1528{ 1529 struct dri_screen *screen = dri_screen(_screen); 1530 struct pipe_screen *pscreen = screen->base.screen; 1531 const struct dri2_format_mapping *map = dri2_get_mapping_by_fourcc(fourcc); 1532 enum pipe_format format; 1533 1534 if (!map) 1535 return false; 1536 1537 format = map->pipe_format; 1538 1539 bool native_sampling = pscreen->is_format_supported(pscreen, format, screen->target, 0, 0, 1540 PIPE_BIND_SAMPLER_VIEW); 1541 if (pscreen->is_format_supported(pscreen, format, screen->target, 0, 0, 1542 PIPE_BIND_RENDER_TARGET) || 1543 native_sampling || 1544 dri2_yuv_dma_buf_supported(screen, map)) { 1545 if (pscreen->query_dmabuf_modifiers != NULL) { 1546 pscreen->query_dmabuf_modifiers(pscreen, format, max, modifiers, 1547 external_only, count); 1548 if (!native_sampling && external_only) { 1549 /* To support it using YUV lowering, we need it to be samplerExternalOES. 1550 */ 1551 for (int i = 0; i < *count; i++) 1552 external_only[i] = true; 1553 } 1554 } else { 1555 *count = 0; 1556 } 1557 return true; 1558 } 1559 return false; 1560} 1561 1562static boolean 1563dri2_query_dma_buf_format_modifier_attribs(__DRIscreen *_screen, 1564 uint32_t fourcc, uint64_t modifier, 1565 int attrib, uint64_t *value) 1566{ 1567 struct dri_screen *screen = dri_screen(_screen); 1568 struct pipe_screen *pscreen = screen->base.screen; 1569 1570 if (!pscreen->query_dmabuf_modifiers) 1571 return false; 1572 1573 switch (attrib) { 1574 case __DRI_IMAGE_FORMAT_MODIFIER_ATTRIB_PLANE_COUNT: { 1575 uint64_t mod_planes = dri2_get_modifier_num_planes(_screen, modifier, 1576 fourcc); 1577 if (mod_planes > 0) 1578 *value = mod_planes; 1579 return mod_planes > 0; 1580 } 1581 default: 1582 return false; 1583 } 1584} 1585 1586static __DRIimage * 1587dri2_from_dma_bufs(__DRIscreen *screen, 1588 int width, int height, int fourcc, 1589 int *fds, int num_fds, 1590 int *strides, int *offsets, 1591 enum __DRIYUVColorSpace yuv_color_space, 1592 enum __DRISampleRange sample_range, 1593 enum __DRIChromaSiting horizontal_siting, 1594 enum __DRIChromaSiting vertical_siting, 1595 unsigned *error, 1596 void *loaderPrivate) 1597{ 1598 __DRIimage *img; 1599 1600 img = dri2_create_image_from_fd(screen, width, height, fourcc, 1601 DRM_FORMAT_MOD_INVALID, fds, num_fds, 1602 strides, offsets, false, error, loaderPrivate); 1603 if (img == NULL) 1604 return NULL; 1605 1606 img->yuv_color_space = yuv_color_space; 1607 img->sample_range = sample_range; 1608 img->horizontal_siting = horizontal_siting; 1609 img->vertical_siting = vertical_siting; 1610 1611 *error = __DRI_IMAGE_ERROR_SUCCESS; 1612 return img; 1613} 1614 1615static __DRIimage * 1616dri2_from_dma_bufs2(__DRIscreen *screen, 1617 int width, int height, int fourcc, 1618 uint64_t modifier, int *fds, int num_fds, 1619 int *strides, int *offsets, 1620 enum __DRIYUVColorSpace yuv_color_space, 1621 enum __DRISampleRange sample_range, 1622 enum __DRIChromaSiting horizontal_siting, 1623 enum __DRIChromaSiting vertical_siting, 1624 unsigned *error, 1625 void *loaderPrivate) 1626{ 1627 __DRIimage *img; 1628 1629 img = dri2_create_image_from_fd(screen, width, height, fourcc, 1630 modifier, fds, num_fds, strides, offsets, 1631 false, error, loaderPrivate); 1632 if (img == NULL) 1633 return NULL; 1634 1635 img->yuv_color_space = yuv_color_space; 1636 img->sample_range = sample_range; 1637 img->horizontal_siting = horizontal_siting; 1638 img->vertical_siting = vertical_siting; 1639 1640 *error = __DRI_IMAGE_ERROR_SUCCESS; 1641 return img; 1642} 1643 1644static __DRIimage * 1645dri2_from_dma_bufs3(__DRIscreen *screen, 1646 int width, int height, int fourcc, 1647 uint64_t modifier, int *fds, int num_fds, 1648 int *strides, int *offsets, 1649 enum __DRIYUVColorSpace yuv_color_space, 1650 enum __DRISampleRange sample_range, 1651 enum __DRIChromaSiting horizontal_siting, 1652 enum __DRIChromaSiting vertical_siting, 1653 uint32_t flags, 1654 unsigned *error, 1655 void *loaderPrivate) 1656{ 1657 __DRIimage *img; 1658 1659 img = dri2_create_image_from_fd(screen, width, height, fourcc, 1660 modifier, fds, num_fds, strides, offsets, 1661 flags & __DRI_IMAGE_PROTECTED_CONTENT_FLAG, 1662 error, loaderPrivate); 1663 if (img == NULL) 1664 return NULL; 1665 1666 img->yuv_color_space = yuv_color_space; 1667 img->sample_range = sample_range; 1668 img->horizontal_siting = horizontal_siting; 1669 img->vertical_siting = vertical_siting; 1670 1671 *error = __DRI_IMAGE_ERROR_SUCCESS; 1672 return img; 1673} 1674 1675static void 1676dri2_blit_image(__DRIcontext *context, __DRIimage *dst, __DRIimage *src, 1677 int dstx0, int dsty0, int dstwidth, int dstheight, 1678 int srcx0, int srcy0, int srcwidth, int srcheight, 1679 int flush_flag) 1680{ 1681 struct dri_context *ctx = dri_context(context); 1682 struct pipe_context *pipe = ctx->st->pipe; 1683 struct pipe_screen *screen; 1684 struct pipe_fence_handle *fence; 1685 struct pipe_blit_info blit; 1686 1687 if (!dst || !src) 1688 return; 1689 1690 memset(&blit, 0, sizeof(blit)); 1691 blit.dst.resource = dst->texture; 1692 blit.dst.box.x = dstx0; 1693 blit.dst.box.y = dsty0; 1694 blit.dst.box.width = dstwidth; 1695 blit.dst.box.height = dstheight; 1696 blit.dst.box.depth = 1; 1697 blit.dst.format = dst->texture->format; 1698 blit.src.resource = src->texture; 1699 blit.src.box.x = srcx0; 1700 blit.src.box.y = srcy0; 1701 blit.src.box.width = srcwidth; 1702 blit.src.box.height = srcheight; 1703 blit.src.box.depth = 1; 1704 blit.src.format = src->texture->format; 1705 blit.mask = PIPE_MASK_RGBA; 1706 blit.filter = PIPE_TEX_FILTER_NEAREST; 1707 blit.is_dri_blit_image = true; 1708 1709 pipe->blit(pipe, &blit); 1710 1711 if (flush_flag == __BLIT_FLAG_FLUSH) { 1712 pipe->flush_resource(pipe, dst->texture); 1713 ctx->st->flush(ctx->st, 0, NULL, NULL, NULL); 1714 } else if (flush_flag == __BLIT_FLAG_FINISH) { 1715 screen = dri_screen(ctx->sPriv)->base.screen; 1716 pipe->flush_resource(pipe, dst->texture); 1717 ctx->st->flush(ctx->st, 0, &fence, NULL, NULL); 1718 (void) screen->fence_finish(screen, NULL, fence, PIPE_TIMEOUT_INFINITE); 1719 screen->fence_reference(screen, &fence, NULL); 1720 } 1721} 1722 1723static void * 1724dri2_map_image(__DRIcontext *context, __DRIimage *image, 1725 int x0, int y0, int width, int height, 1726 unsigned int flags, int *stride, void **data) 1727{ 1728 struct dri_context *ctx = dri_context(context); 1729 struct pipe_context *pipe = ctx->st->pipe; 1730 enum pipe_map_flags pipe_access = 0; 1731 struct pipe_transfer *trans; 1732 void *map; 1733 1734 if (!image || !data || *data) 1735 return NULL; 1736 1737 unsigned plane = image->plane; 1738 if (plane >= dri2_get_mapping_by_format(image->dri_format)->nplanes) 1739 return NULL; 1740 1741 struct pipe_resource *resource = image->texture; 1742 while (plane--) 1743 resource = resource->next; 1744 1745 if (flags & __DRI_IMAGE_TRANSFER_READ) 1746 pipe_access |= PIPE_MAP_READ; 1747 if (flags & __DRI_IMAGE_TRANSFER_WRITE) 1748 pipe_access |= PIPE_MAP_WRITE; 1749 1750 map = pipe_texture_map(pipe, resource, 0, 0, pipe_access, x0, y0, 1751 width, height, &trans); 1752 if (map) { 1753 *data = trans; 1754 *stride = trans->stride; 1755 } 1756 1757 return map; 1758} 1759 1760static void 1761dri2_unmap_image(__DRIcontext *context, __DRIimage *image, void *data) 1762{ 1763 struct dri_context *ctx = dri_context(context); 1764 struct pipe_context *pipe = ctx->st->pipe; 1765 1766 pipe_texture_unmap(pipe, (struct pipe_transfer *)data); 1767} 1768 1769static int 1770dri2_get_capabilities(__DRIscreen *_screen) 1771{ 1772 struct dri_screen *screen = dri_screen(_screen); 1773 1774 return (screen->can_share_buffer ? __DRI_IMAGE_CAP_GLOBAL_NAMES : 0); 1775} 1776 1777/* The extension is modified during runtime if DRI_PRIME is detected */ 1778static const __DRIimageExtension dri2ImageExtensionTempl = { 1779 .base = { __DRI_IMAGE, 19 }, 1780 1781 .createImageFromName = dri2_create_image_from_name, 1782 .createImageFromRenderbuffer = dri2_create_image_from_renderbuffer, 1783 .destroyImage = dri2_destroy_image, 1784 .createImage = dri2_create_image, 1785 .queryImage = dri2_query_image, 1786 .dupImage = dri2_dup_image, 1787 .validateUsage = dri2_validate_usage, 1788 .createImageFromNames = dri2_from_names, 1789 .fromPlanar = dri2_from_planar, 1790 .createImageFromTexture = dri2_create_from_texture, 1791 .createImageFromFds = NULL, 1792 .createImageFromDmaBufs = NULL, 1793 .blitImage = dri2_blit_image, 1794 .getCapabilities = dri2_get_capabilities, 1795 .mapImage = dri2_map_image, 1796 .unmapImage = dri2_unmap_image, 1797 .createImageWithModifiers = NULL, 1798 .createImageFromDmaBufs2 = NULL, 1799 .createImageFromDmaBufs3 = NULL, 1800 .queryDmaBufFormats = NULL, 1801 .queryDmaBufModifiers = NULL, 1802 .queryDmaBufFormatModifierAttribs = NULL, 1803 .createImageFromRenderbuffer2 = dri2_create_image_from_renderbuffer2, 1804 .createImageWithModifiers2 = NULL, 1805}; 1806 1807static const __DRIrobustnessExtension dri2Robustness = { 1808 .base = { __DRI2_ROBUSTNESS, 1 } 1809}; 1810 1811static int 1812dri2_interop_query_device_info(__DRIcontext *_ctx, 1813 struct mesa_glinterop_device_info *out) 1814{ 1815 struct pipe_screen *screen = dri_context(_ctx)->st->pipe->screen; 1816 1817 /* There is no version 0, thus we do not support it */ 1818 if (out->version == 0) 1819 return MESA_GLINTEROP_INVALID_VERSION; 1820 1821 out->pci_segment_group = screen->get_param(screen, PIPE_CAP_PCI_GROUP); 1822 out->pci_bus = screen->get_param(screen, PIPE_CAP_PCI_BUS); 1823 out->pci_device = screen->get_param(screen, PIPE_CAP_PCI_DEVICE); 1824 out->pci_function = screen->get_param(screen, PIPE_CAP_PCI_FUNCTION); 1825 1826 out->vendor_id = screen->get_param(screen, PIPE_CAP_VENDOR_ID); 1827 out->device_id = screen->get_param(screen, PIPE_CAP_DEVICE_ID); 1828 1829 /* Instruct the caller that we support up-to version one of the interface */ 1830 out->version = 1; 1831 1832 return MESA_GLINTEROP_SUCCESS; 1833} 1834 1835static int 1836dri2_interop_export_object(__DRIcontext *_ctx, 1837 struct mesa_glinterop_export_in *in, 1838 struct mesa_glinterop_export_out *out) 1839{ 1840 struct st_context_iface *st = dri_context(_ctx)->st; 1841 struct pipe_screen *screen = st->pipe->screen; 1842 struct gl_context *ctx = ((struct st_context *)st)->ctx; 1843 struct pipe_resource *res = NULL; 1844 struct winsys_handle whandle; 1845 unsigned target, usage; 1846 boolean success; 1847 1848 /* There is no version 0, thus we do not support it */ 1849 if (in->version == 0 || out->version == 0) 1850 return MESA_GLINTEROP_INVALID_VERSION; 1851 1852 /* Validate the target. */ 1853 switch (in->target) { 1854 case GL_TEXTURE_BUFFER: 1855 case GL_TEXTURE_1D: 1856 case GL_TEXTURE_2D: 1857 case GL_TEXTURE_3D: 1858 case GL_TEXTURE_RECTANGLE: 1859 case GL_TEXTURE_1D_ARRAY: 1860 case GL_TEXTURE_2D_ARRAY: 1861 case GL_TEXTURE_CUBE_MAP_ARRAY: 1862 case GL_TEXTURE_CUBE_MAP: 1863 case GL_TEXTURE_2D_MULTISAMPLE: 1864 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: 1865 case GL_TEXTURE_EXTERNAL_OES: 1866 case GL_RENDERBUFFER: 1867 case GL_ARRAY_BUFFER: 1868 target = in->target; 1869 break; 1870 case GL_TEXTURE_CUBE_MAP_POSITIVE_X: 1871 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: 1872 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: 1873 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: 1874 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: 1875 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: 1876 target = GL_TEXTURE_CUBE_MAP; 1877 break; 1878 default: 1879 return MESA_GLINTEROP_INVALID_TARGET; 1880 } 1881 1882 /* Validate the simple case of miplevel. */ 1883 if ((target == GL_RENDERBUFFER || target == GL_ARRAY_BUFFER) && 1884 in->miplevel != 0) 1885 return MESA_GLINTEROP_INVALID_MIP_LEVEL; 1886 1887 /* Validate the OpenGL object and get pipe_resource. */ 1888 simple_mtx_lock(&ctx->Shared->Mutex); 1889 1890 if (target == GL_ARRAY_BUFFER) { 1891 /* Buffer objects. 1892 * 1893 * The error checking is based on the documentation of 1894 * clCreateFromGLBuffer from OpenCL 2.0 SDK. 1895 */ 1896 struct gl_buffer_object *buf = _mesa_lookup_bufferobj(ctx, in->obj); 1897 1898 /* From OpenCL 2.0 SDK, clCreateFromGLBuffer: 1899 * "CL_INVALID_GL_OBJECT if bufobj is not a GL buffer object or is 1900 * a GL buffer object but does not have an existing data store or 1901 * the size of the buffer is 0." 1902 */ 1903 if (!buf || buf->Size == 0) { 1904 simple_mtx_unlock(&ctx->Shared->Mutex); 1905 return MESA_GLINTEROP_INVALID_OBJECT; 1906 } 1907 1908 res = st_buffer_object(buf)->buffer; 1909 if (!res) { 1910 /* this shouldn't happen */ 1911 simple_mtx_unlock(&ctx->Shared->Mutex); 1912 return MESA_GLINTEROP_INVALID_OBJECT; 1913 } 1914 1915 out->buf_offset = 0; 1916 out->buf_size = buf->Size; 1917 1918 buf->UsageHistory |= USAGE_DISABLE_MINMAX_CACHE; 1919 } else if (target == GL_RENDERBUFFER) { 1920 /* Renderbuffers. 1921 * 1922 * The error checking is based on the documentation of 1923 * clCreateFromGLRenderbuffer from OpenCL 2.0 SDK. 1924 */ 1925 struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, in->obj); 1926 1927 /* From OpenCL 2.0 SDK, clCreateFromGLRenderbuffer: 1928 * "CL_INVALID_GL_OBJECT if renderbuffer is not a GL renderbuffer 1929 * object or if the width or height of renderbuffer is zero." 1930 */ 1931 if (!rb || rb->Width == 0 || rb->Height == 0) { 1932 simple_mtx_unlock(&ctx->Shared->Mutex); 1933 return MESA_GLINTEROP_INVALID_OBJECT; 1934 } 1935 1936 /* From OpenCL 2.0 SDK, clCreateFromGLRenderbuffer: 1937 * "CL_INVALID_OPERATION if renderbuffer is a multi-sample GL 1938 * renderbuffer object." 1939 */ 1940 if (rb->NumSamples > 1) { 1941 simple_mtx_unlock(&ctx->Shared->Mutex); 1942 return MESA_GLINTEROP_INVALID_OPERATION; 1943 } 1944 1945 /* From OpenCL 2.0 SDK, clCreateFromGLRenderbuffer: 1946 * "CL_OUT_OF_RESOURCES if there is a failure to allocate resources 1947 * required by the OpenCL implementation on the device." 1948 */ 1949 res = st_renderbuffer(rb)->texture; 1950 if (!res) { 1951 simple_mtx_unlock(&ctx->Shared->Mutex); 1952 return MESA_GLINTEROP_OUT_OF_RESOURCES; 1953 } 1954 1955 out->internal_format = rb->InternalFormat; 1956 out->view_minlevel = 0; 1957 out->view_numlevels = 1; 1958 out->view_minlayer = 0; 1959 out->view_numlayers = 1; 1960 } else { 1961 /* Texture objects. 1962 * 1963 * The error checking is based on the documentation of 1964 * clCreateFromGLTexture from OpenCL 2.0 SDK. 1965 */ 1966 struct gl_texture_object *obj = _mesa_lookup_texture(ctx, in->obj); 1967 1968 if (obj) 1969 _mesa_test_texobj_completeness(ctx, obj); 1970 1971 /* From OpenCL 2.0 SDK, clCreateFromGLTexture: 1972 * "CL_INVALID_GL_OBJECT if texture is not a GL texture object whose 1973 * type matches texture_target, if the specified miplevel of texture 1974 * is not defined, or if the width or height of the specified 1975 * miplevel is zero or if the GL texture object is incomplete." 1976 */ 1977 if (!obj || 1978 obj->Target != target || 1979 !obj->_BaseComplete || 1980 (in->miplevel > 0 && !obj->_MipmapComplete)) { 1981 simple_mtx_unlock(&ctx->Shared->Mutex); 1982 return MESA_GLINTEROP_INVALID_OBJECT; 1983 } 1984 1985 if (target == GL_TEXTURE_BUFFER) { 1986 struct st_buffer_object *stBuf = 1987 st_buffer_object(obj->BufferObject); 1988 1989 if (!stBuf || !stBuf->buffer) { 1990 /* this shouldn't happen */ 1991 simple_mtx_unlock(&ctx->Shared->Mutex); 1992 return MESA_GLINTEROP_INVALID_OBJECT; 1993 } 1994 res = stBuf->buffer; 1995 1996 out->internal_format = obj->BufferObjectFormat; 1997 out->buf_offset = obj->BufferOffset; 1998 out->buf_size = obj->BufferSize == -1 ? obj->BufferObject->Size : 1999 obj->BufferSize; 2000 2001 obj->BufferObject->UsageHistory |= USAGE_DISABLE_MINMAX_CACHE; 2002 } else { 2003 /* From OpenCL 2.0 SDK, clCreateFromGLTexture: 2004 * "CL_INVALID_MIP_LEVEL if miplevel is less than the value of 2005 * levelbase (for OpenGL implementations) or zero (for OpenGL ES 2006 * implementations); or greater than the value of q (for both OpenGL 2007 * and OpenGL ES). levelbase and q are defined for the texture in 2008 * section 3.8.10 (Texture Completeness) of the OpenGL 2.1 2009 * specification and section 3.7.10 of the OpenGL ES 2.0." 2010 */ 2011 if (in->miplevel < obj->Attrib.BaseLevel || in->miplevel > obj->_MaxLevel) { 2012 simple_mtx_unlock(&ctx->Shared->Mutex); 2013 return MESA_GLINTEROP_INVALID_MIP_LEVEL; 2014 } 2015 2016 if (!st_finalize_texture(ctx, st->pipe, obj, 0)) { 2017 simple_mtx_unlock(&ctx->Shared->Mutex); 2018 return MESA_GLINTEROP_OUT_OF_RESOURCES; 2019 } 2020 2021 res = st_get_texobj_resource(obj); 2022 if (!res) { 2023 /* Incomplete texture buffer object? This shouldn't really occur. */ 2024 simple_mtx_unlock(&ctx->Shared->Mutex); 2025 return MESA_GLINTEROP_INVALID_OBJECT; 2026 } 2027 2028 out->internal_format = obj->Image[0][0]->InternalFormat; 2029 out->view_minlevel = obj->Attrib.MinLevel; 2030 out->view_numlevels = obj->Attrib.NumLevels; 2031 out->view_minlayer = obj->Attrib.MinLayer; 2032 out->view_numlayers = obj->Attrib.NumLayers; 2033 } 2034 } 2035 2036 /* Get the handle. */ 2037 switch (in->access) { 2038 case MESA_GLINTEROP_ACCESS_READ_ONLY: 2039 usage = 0; 2040 break; 2041 case MESA_GLINTEROP_ACCESS_READ_WRITE: 2042 case MESA_GLINTEROP_ACCESS_WRITE_ONLY: 2043 usage = PIPE_HANDLE_USAGE_SHADER_WRITE; 2044 break; 2045 default: 2046 usage = 0; 2047 } 2048 2049 memset(&whandle, 0, sizeof(whandle)); 2050 whandle.type = WINSYS_HANDLE_TYPE_FD; 2051 2052 success = screen->resource_get_handle(screen, st->pipe, res, &whandle, 2053 usage); 2054 simple_mtx_unlock(&ctx->Shared->Mutex); 2055 2056 if (!success) 2057 return MESA_GLINTEROP_OUT_OF_HOST_MEMORY; 2058 2059 out->dmabuf_fd = whandle.handle; 2060 out->out_driver_data_written = 0; 2061 2062 if (res->target == PIPE_BUFFER) 2063 out->buf_offset += whandle.offset; 2064 2065 /* Instruct the caller that we support up-to version one of the interface */ 2066 in->version = 1; 2067 out->version = 1; 2068 2069 return MESA_GLINTEROP_SUCCESS; 2070} 2071 2072static const __DRI2interopExtension dri2InteropExtension = { 2073 .base = { __DRI2_INTEROP, 1 }, 2074 .query_device_info = dri2_interop_query_device_info, 2075 .export_object = dri2_interop_export_object 2076}; 2077 2078/** 2079 * \brief the DRI2bufferDamageExtension set_damage_region method 2080 */ 2081static void 2082dri2_set_damage_region(__DRIdrawable *dPriv, unsigned int nrects, int *rects) 2083{ 2084 struct dri_drawable *drawable = dri_drawable(dPriv); 2085 struct pipe_box *boxes = NULL; 2086 2087 if (nrects) { 2088 boxes = CALLOC(nrects, sizeof(*boxes)); 2089 assert(boxes); 2090 2091 for (unsigned int i = 0; i < nrects; i++) { 2092 int *rect = &rects[i * 4]; 2093 2094 u_box_2d(rect[0], rect[1], rect[2], rect[3], &boxes[i]); 2095 } 2096 } 2097 2098 FREE(drawable->damage_rects); 2099 drawable->damage_rects = boxes; 2100 drawable->num_damage_rects = nrects; 2101 2102 /* Only apply the damage region if the BACK_LEFT texture is up-to-date. */ 2103 if (drawable->texture_stamp == drawable->dPriv->lastStamp && 2104 (drawable->texture_mask & (1 << ST_ATTACHMENT_BACK_LEFT))) { 2105 struct pipe_screen *screen = drawable->screen->base.screen; 2106 struct pipe_resource *resource; 2107 2108 if (drawable->stvis.samples > 1) 2109 resource = drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT]; 2110 else 2111 resource = drawable->textures[ST_ATTACHMENT_BACK_LEFT]; 2112 2113 screen->set_damage_region(screen, resource, 2114 drawable->num_damage_rects, 2115 drawable->damage_rects); 2116 } 2117} 2118 2119static const __DRI2bufferDamageExtension dri2BufferDamageExtensionTempl = { 2120 .base = { __DRI2_BUFFER_DAMAGE, 1 }, 2121}; 2122 2123/** 2124 * \brief the DRI2ConfigQueryExtension configQueryb method 2125 */ 2126static int 2127dri2GalliumConfigQueryb(__DRIscreen *sPriv, const char *var, 2128 unsigned char *val) 2129{ 2130 struct dri_screen *screen = dri_screen(sPriv); 2131 2132 if (!driCheckOption(&screen->dev->option_cache, var, DRI_BOOL)) 2133 return dri2ConfigQueryExtension.configQueryb(sPriv, var, val); 2134 2135 *val = driQueryOptionb(&screen->dev->option_cache, var); 2136 2137 return 0; 2138} 2139 2140/** 2141 * \brief the DRI2ConfigQueryExtension configQueryi method 2142 */ 2143static int 2144dri2GalliumConfigQueryi(__DRIscreen *sPriv, const char *var, int *val) 2145{ 2146 struct dri_screen *screen = dri_screen(sPriv); 2147 2148 if (!driCheckOption(&screen->dev->option_cache, var, DRI_INT) && 2149 !driCheckOption(&screen->dev->option_cache, var, DRI_ENUM)) 2150 return dri2ConfigQueryExtension.configQueryi(sPriv, var, val); 2151 2152 *val = driQueryOptioni(&screen->dev->option_cache, var); 2153 2154 return 0; 2155} 2156 2157/** 2158 * \brief the DRI2ConfigQueryExtension configQueryf method 2159 */ 2160static int 2161dri2GalliumConfigQueryf(__DRIscreen *sPriv, const char *var, float *val) 2162{ 2163 struct dri_screen *screen = dri_screen(sPriv); 2164 2165 if (!driCheckOption(&screen->dev->option_cache, var, DRI_FLOAT)) 2166 return dri2ConfigQueryExtension.configQueryf(sPriv, var, val); 2167 2168 *val = driQueryOptionf(&screen->dev->option_cache, var); 2169 2170 return 0; 2171} 2172 2173/** 2174 * \brief the DRI2ConfigQueryExtension configQuerys method 2175 */ 2176static int 2177dri2GalliumConfigQuerys(__DRIscreen *sPriv, const char *var, char **val) 2178{ 2179 struct dri_screen *screen = dri_screen(sPriv); 2180 2181 if (!driCheckOption(&screen->dev->option_cache, var, DRI_STRING)) 2182 return dri2ConfigQueryExtension.configQuerys(sPriv, var, val); 2183 2184 *val = driQueryOptionstr(&screen->dev->option_cache, var); 2185 2186 return 0; 2187} 2188 2189/** 2190 * \brief the DRI2ConfigQueryExtension struct. 2191 * 2192 * We first query the driver option cache. Then the dri2 option cache. 2193 */ 2194static const __DRI2configQueryExtension dri2GalliumConfigQueryExtension = { 2195 .base = { __DRI2_CONFIG_QUERY, 2 }, 2196 2197 .configQueryb = dri2GalliumConfigQueryb, 2198 .configQueryi = dri2GalliumConfigQueryi, 2199 .configQueryf = dri2GalliumConfigQueryf, 2200 .configQuerys = dri2GalliumConfigQuerys, 2201}; 2202 2203/** 2204 * \brief the DRI2blobExtension set_cache_funcs method 2205 */ 2206static void 2207set_blob_cache_funcs(__DRIscreen *sPriv, __DRIblobCacheSet set, 2208 __DRIblobCacheGet get) 2209{ 2210 struct dri_screen *screen = dri_screen(sPriv); 2211 struct pipe_screen *pscreen = screen->base.screen; 2212 2213 if (!pscreen->get_disk_shader_cache) 2214 return; 2215 2216 struct disk_cache *cache = pscreen->get_disk_shader_cache(pscreen); 2217 2218 if (!cache) 2219 return; 2220 2221 disk_cache_set_callbacks(cache, set, get); 2222} 2223 2224static const __DRI2blobExtension driBlobExtension = { 2225 .base = { __DRI2_BLOB, 1 }, 2226 .set_cache_funcs = set_blob_cache_funcs 2227}; 2228 2229static const __DRImutableRenderBufferDriverExtension driMutableRenderBufferExtension = { 2230 .base = { __DRI_MUTABLE_RENDER_BUFFER_DRIVER, 1 }, 2231}; 2232 2233/* 2234 * Backend function init_screen. 2235 */ 2236 2237static const __DRIextension *dri_screen_extensions_base[] = { 2238 &driTexBufferExtension.base, 2239 &dri2FlushExtension.base, 2240 &dri2RendererQueryExtension.base, 2241 &dri2GalliumConfigQueryExtension.base, 2242 &dri2ThrottleExtension.base, 2243 &dri2FenceExtension.base, 2244 &dri2InteropExtension.base, 2245 &dri2NoErrorExtension.base, 2246 &driBlobExtension.base, 2247 &driMutableRenderBufferExtension.base, 2248}; 2249 2250/** 2251 * Set up the DRI extension list for this screen based on its underlying 2252 * gallium screen's capabilities. 2253 */ 2254static void 2255dri2_init_screen_extensions(struct dri_screen *screen, 2256 struct pipe_screen *pscreen, 2257 bool is_kms_screen) 2258{ 2259 const __DRIextension **nExt; 2260 2261 STATIC_ASSERT(sizeof(screen->screen_extensions) >= 2262 sizeof(dri_screen_extensions_base)); 2263 memcpy(&screen->screen_extensions, dri_screen_extensions_base, 2264 sizeof(dri_screen_extensions_base)); 2265 screen->sPriv->extensions = screen->screen_extensions; 2266 2267 /* Point nExt at the end of the extension list */ 2268 nExt = &screen->screen_extensions[ARRAY_SIZE(dri_screen_extensions_base)]; 2269 2270 screen->image_extension = dri2ImageExtensionTempl; 2271 if (pscreen->resource_create_with_modifiers) { 2272 screen->image_extension.createImageWithModifiers = 2273 dri2_create_image_with_modifiers; 2274 screen->image_extension.createImageWithModifiers2 = 2275 dri2_create_image_with_modifiers2; 2276 } 2277 2278 if (pscreen->get_param(pscreen, PIPE_CAP_DMABUF)) { 2279 uint64_t cap; 2280 2281 if (drmGetCap(screen->sPriv->fd, DRM_CAP_PRIME, &cap) == 0 && 2282 (cap & DRM_PRIME_CAP_IMPORT)) { 2283 screen->image_extension.createImageFromFds = dri2_from_fds; 2284 screen->image_extension.createImageFromDmaBufs = dri2_from_dma_bufs; 2285 screen->image_extension.createImageFromDmaBufs2 = dri2_from_dma_bufs2; 2286 screen->image_extension.createImageFromDmaBufs3 = dri2_from_dma_bufs3; 2287 screen->image_extension.queryDmaBufFormats = 2288 dri2_query_dma_buf_formats; 2289 screen->image_extension.queryDmaBufModifiers = 2290 dri2_query_dma_buf_modifiers; 2291 if (!is_kms_screen) { 2292 screen->image_extension.queryDmaBufFormatModifierAttribs = 2293 dri2_query_dma_buf_format_modifier_attribs; 2294 } 2295 } 2296 } 2297 *nExt++ = &screen->image_extension.base; 2298 2299 if (!is_kms_screen) { 2300 screen->buffer_damage_extension = dri2BufferDamageExtensionTempl; 2301 if (pscreen->set_damage_region) 2302 screen->buffer_damage_extension.set_damage_region = 2303 dri2_set_damage_region; 2304 *nExt++ = &screen->buffer_damage_extension.base; 2305 2306 if (pscreen->get_param(pscreen, PIPE_CAP_DEVICE_RESET_STATUS_QUERY)) { 2307 *nExt++ = &dri2Robustness.base; 2308 screen->has_reset_status_query = true; 2309 } 2310 } 2311 2312 /* Ensure the extension list didn't overrun its buffer and is still 2313 * NULL-terminated */ 2314 assert(nExt - screen->screen_extensions <= 2315 ARRAY_SIZE(screen->screen_extensions) - 1); 2316 assert(!*nExt); 2317} 2318 2319/** 2320 * This is the driver specific part of the createNewScreen entry point. 2321 * 2322 * Returns the struct gl_config supported by this driver. 2323 */ 2324static const __DRIconfig ** 2325dri2_init_screen(__DRIscreen * sPriv) 2326{ 2327 const __DRIconfig **configs; 2328 struct dri_screen *screen; 2329 struct pipe_screen *pscreen = NULL; 2330 2331 screen = CALLOC_STRUCT(dri_screen); 2332 if (!screen) 2333 return NULL; 2334 2335 screen->sPriv = sPriv; 2336 screen->fd = sPriv->fd; 2337 (void) mtx_init(&screen->opencl_func_mutex, mtx_plain); 2338 2339 sPriv->driverPrivate = (void *)screen; 2340 2341 if (pipe_loader_drm_probe_fd(&screen->dev, screen->fd)) { 2342 pscreen = pipe_loader_create_screen(screen->dev); 2343 dri_init_options(screen); 2344 } 2345 2346 if (!pscreen) 2347 goto release_pipe; 2348 2349 screen->throttle = pscreen->get_param(pscreen, PIPE_CAP_THROTTLE); 2350 2351 dri2_init_screen_extensions(screen, pscreen, false); 2352 2353 configs = dri_init_screen_helper(screen, pscreen); 2354 if (!configs) 2355 goto destroy_screen; 2356 2357 screen->can_share_buffer = true; 2358 screen->auto_fake_front = dri_with_format(sPriv); 2359 screen->broken_invalidate = !sPriv->dri2.useInvalidate; 2360 screen->lookup_egl_image = dri2_lookup_egl_image; 2361 2362 const __DRIimageLookupExtension *loader = sPriv->dri2.image; 2363 if (loader && 2364 loader->base.version >= 2 && 2365 loader->validateEGLImage && 2366 loader->lookupEGLImageValidated) { 2367 screen->validate_egl_image = dri2_validate_egl_image; 2368 screen->lookup_egl_image_validated = dri2_lookup_egl_image_validated; 2369 } 2370 2371 return configs; 2372 2373destroy_screen: 2374 dri_destroy_screen_helper(screen); 2375 2376release_pipe: 2377 if (screen->dev) 2378 pipe_loader_release(&screen->dev, 1); 2379 2380 FREE(screen); 2381 return NULL; 2382} 2383 2384/** 2385 * This is the driver specific part of the createNewScreen entry point. 2386 * 2387 * Returns the struct gl_config supported by this driver. 2388 */ 2389static const __DRIconfig ** 2390dri_kms_init_screen(__DRIscreen * sPriv) 2391{ 2392#if defined(GALLIUM_SOFTPIPE) 2393 const __DRIconfig **configs; 2394 struct dri_screen *screen; 2395 struct pipe_screen *pscreen = NULL; 2396 2397 screen = CALLOC_STRUCT(dri_screen); 2398 if (!screen) 2399 return NULL; 2400 2401 screen->sPriv = sPriv; 2402 screen->fd = sPriv->fd; 2403 2404 sPriv->driverPrivate = (void *)screen; 2405 2406 if (pipe_loader_sw_probe_kms(&screen->dev, screen->fd)) { 2407 pscreen = pipe_loader_create_screen(screen->dev); 2408 dri_init_options(screen); 2409 } 2410 2411 if (!pscreen) 2412 goto release_pipe; 2413 2414 dri2_init_screen_extensions(screen, pscreen, true); 2415 2416 configs = dri_init_screen_helper(screen, pscreen); 2417 if (!configs) 2418 goto destroy_screen; 2419 2420 screen->can_share_buffer = false; 2421 screen->auto_fake_front = dri_with_format(sPriv); 2422 screen->broken_invalidate = !sPriv->dri2.useInvalidate; 2423 screen->lookup_egl_image = dri2_lookup_egl_image; 2424 2425 const __DRIimageLookupExtension *loader = sPriv->dri2.image; 2426 if (loader && 2427 loader->base.version >= 2 && 2428 loader->validateEGLImage && 2429 loader->lookupEGLImageValidated) { 2430 screen->validate_egl_image = dri2_validate_egl_image; 2431 screen->lookup_egl_image_validated = dri2_lookup_egl_image_validated; 2432 } 2433 2434 return configs; 2435 2436destroy_screen: 2437 dri_destroy_screen_helper(screen); 2438 2439release_pipe: 2440 if (screen->dev) 2441 pipe_loader_release(&screen->dev, 1); 2442 2443 FREE(screen); 2444#endif // GALLIUM_SOFTPIPE 2445 return NULL; 2446} 2447 2448static boolean 2449dri2_create_buffer(__DRIscreen * sPriv, 2450 __DRIdrawable * dPriv, 2451 const struct gl_config * visual, boolean isPixmap) 2452{ 2453 struct dri_drawable *drawable = NULL; 2454 2455 if (!dri_create_buffer(sPriv, dPriv, visual, isPixmap)) 2456 return FALSE; 2457 2458 drawable = dPriv->driverPrivate; 2459 2460 drawable->allocate_textures = dri2_allocate_textures; 2461 drawable->flush_frontbuffer = dri2_flush_frontbuffer; 2462 drawable->update_tex_buffer = dri2_update_tex_buffer; 2463 drawable->flush_swapbuffers = dri2_flush_swapbuffers; 2464 2465 return TRUE; 2466} 2467 2468/** 2469 * DRI driver virtual function table. 2470 * 2471 * DRI versions differ in their implementation of init_screen and swap_buffers. 2472 */ 2473const struct __DriverAPIRec galliumdrm_driver_api = { 2474 .InitScreen = dri2_init_screen, 2475 .DestroyScreen = dri_destroy_screen, 2476 .CreateContext = dri_create_context, 2477 .DestroyContext = dri_destroy_context, 2478 .CreateBuffer = dri2_create_buffer, 2479 .DestroyBuffer = dri_destroy_buffer, 2480 .MakeCurrent = dri_make_current, 2481 .UnbindContext = dri_unbind_context, 2482 2483 .AllocateBuffer = dri2_allocate_buffer, 2484 .ReleaseBuffer = dri2_release_buffer, 2485}; 2486 2487/** 2488 * DRI driver virtual function table. 2489 * 2490 * KMS/DRM version of the DriverAPI above sporting a different InitScreen 2491 * hook. The latter is used to explicitly initialise the kms_swrast driver 2492 * rather than selecting the approapriate driver as suggested by the loader. 2493 */ 2494const struct __DriverAPIRec dri_kms_driver_api = { 2495 .InitScreen = dri_kms_init_screen, 2496 .DestroyScreen = dri_destroy_screen, 2497 .CreateContext = dri_create_context, 2498 .DestroyContext = dri_destroy_context, 2499 .CreateBuffer = dri2_create_buffer, 2500 .DestroyBuffer = dri_destroy_buffer, 2501 .MakeCurrent = dri_make_current, 2502 .UnbindContext = dri_unbind_context, 2503 2504 .AllocateBuffer = dri2_allocate_buffer, 2505 .ReleaseBuffer = dri2_release_buffer, 2506}; 2507 2508/* This is the table of extensions that the loader will dlsym() for. */ 2509const __DRIextension *galliumdrm_driver_extensions[] = { 2510 &driCoreExtension.base, 2511 &driImageDriverExtension.base, 2512 &driDRI2Extension.base, 2513 &gallium_config_options.base, 2514 NULL 2515}; 2516 2517/* vim: set sw=3 ts=8 sts=3 expandtab: */ 2518