1/* 2 * Copyright © 2014-2018 NVIDIA 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 24#include <errno.h> 25#include <fcntl.h> 26#include <inttypes.h> 27#include <stdio.h> 28 29#include <sys/stat.h> 30 31#include "drm-uapi/drm_fourcc.h" 32#include "drm-uapi/tegra_drm.h" 33#include <xf86drm.h> 34 35#include "loader/loader.h" 36#include "pipe/p_state.h" 37#include "util/u_debug.h" 38#include "util/format/u_format.h" 39#include "util/u_inlines.h" 40 41#include "frontend/drm_driver.h" 42 43#include "nouveau/drm/nouveau_drm_public.h" 44 45#include "tegra_context.h" 46#include "tegra_resource.h" 47#include "tegra_screen.h" 48 49static void tegra_screen_destroy(struct pipe_screen *pscreen) 50{ 51 struct tegra_screen *screen = to_tegra_screen(pscreen); 52 53 screen->gpu->destroy(screen->gpu); 54 free(pscreen); 55} 56 57static const char * 58tegra_screen_get_name(struct pipe_screen *pscreen) 59{ 60 return "tegra"; 61} 62 63static const char * 64tegra_screen_get_vendor(struct pipe_screen *pscreen) 65{ 66 return "NVIDIA"; 67} 68 69static const char * 70tegra_screen_get_device_vendor(struct pipe_screen *pscreen) 71{ 72 return "NVIDIA"; 73} 74 75static int 76tegra_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param) 77{ 78 struct tegra_screen *screen = to_tegra_screen(pscreen); 79 80 return screen->gpu->get_param(screen->gpu, param); 81} 82 83static float 84tegra_screen_get_paramf(struct pipe_screen *pscreen, enum pipe_capf param) 85{ 86 struct tegra_screen *screen = to_tegra_screen(pscreen); 87 88 return screen->gpu->get_paramf(screen->gpu, param); 89} 90 91static int 92tegra_screen_get_shader_param(struct pipe_screen *pscreen, unsigned shader, 93 enum pipe_shader_cap param) 94{ 95 struct tegra_screen *screen = to_tegra_screen(pscreen); 96 97 return screen->gpu->get_shader_param(screen->gpu, shader, param); 98} 99 100static int 101tegra_screen_get_video_param(struct pipe_screen *pscreen, 102 enum pipe_video_profile profile, 103 enum pipe_video_entrypoint entrypoint, 104 enum pipe_video_cap param) 105{ 106 struct tegra_screen *screen = to_tegra_screen(pscreen); 107 108 return screen->gpu->get_video_param(screen->gpu, profile, entrypoint, 109 param); 110} 111 112static int 113tegra_screen_get_compute_param(struct pipe_screen *pscreen, 114 enum pipe_shader_ir ir_type, 115 enum pipe_compute_cap param, 116 void *retp) 117{ 118 struct tegra_screen *screen = to_tegra_screen(pscreen); 119 120 return screen->gpu->get_compute_param(screen->gpu, ir_type, param, 121 retp); 122} 123 124static uint64_t 125tegra_screen_get_timestamp(struct pipe_screen *pscreen) 126{ 127 struct tegra_screen *screen = to_tegra_screen(pscreen); 128 129 return screen->gpu->get_timestamp(screen->gpu); 130} 131 132static bool 133tegra_screen_is_format_supported(struct pipe_screen *pscreen, 134 enum pipe_format format, 135 enum pipe_texture_target target, 136 unsigned sample_count, 137 unsigned storage_sample_count, 138 unsigned usage) 139{ 140 struct tegra_screen *screen = to_tegra_screen(pscreen); 141 142 return screen->gpu->is_format_supported(screen->gpu, format, target, 143 sample_count, storage_sample_count, 144 usage); 145} 146 147static bool 148tegra_screen_is_video_format_supported(struct pipe_screen *pscreen, 149 enum pipe_format format, 150 enum pipe_video_profile profile, 151 enum pipe_video_entrypoint entrypoint) 152{ 153 struct tegra_screen *screen = to_tegra_screen(pscreen); 154 155 return screen->gpu->is_video_format_supported(screen->gpu, format, profile, 156 entrypoint); 157} 158 159static bool 160tegra_screen_can_create_resource(struct pipe_screen *pscreen, 161 const struct pipe_resource *template) 162{ 163 struct tegra_screen *screen = to_tegra_screen(pscreen); 164 165 return screen->gpu->can_create_resource(screen->gpu, template); 166} 167 168static int tegra_screen_import_resource(struct tegra_screen *screen, 169 struct tegra_resource *resource) 170{ 171 struct winsys_handle handle; 172 bool status; 173 int fd, err; 174 175 memset(&handle, 0, sizeof(handle)); 176 handle.modifier = DRM_FORMAT_MOD_INVALID; 177 handle.type = WINSYS_HANDLE_TYPE_FD; 178 179 status = screen->gpu->resource_get_handle(screen->gpu, NULL, resource->gpu, 180 &handle, 0); 181 if (!status) 182 return -EINVAL; 183 184 assert(handle.modifier != DRM_FORMAT_MOD_INVALID); 185 186 if (handle.modifier == DRM_FORMAT_MOD_INVALID) { 187 close(handle.handle); 188 return -EINVAL; 189 } 190 191 resource->modifier = handle.modifier; 192 resource->stride = handle.stride; 193 fd = handle.handle; 194 195 err = drmPrimeFDToHandle(screen->fd, fd, &resource->handle); 196 if (err < 0) 197 err = -errno; 198 199 close(fd); 200 201 return err; 202} 203 204static struct pipe_resource * 205tegra_screen_resource_create(struct pipe_screen *pscreen, 206 const struct pipe_resource *template) 207{ 208 struct tegra_screen *screen = to_tegra_screen(pscreen); 209 uint64_t modifier = DRM_FORMAT_MOD_INVALID; 210 struct tegra_resource *resource; 211 int err; 212 213 resource = calloc(1, sizeof(*resource)); 214 if (!resource) 215 return NULL; 216 217 /* 218 * Applications that create scanout resources without modifiers are very 219 * unlikely to support modifiers at all. In that case the resources need 220 * to be created with a pitch-linear layout so that they can be properly 221 * shared with scanout hardware. 222 * 223 * Technically it is possible for applications to create resources without 224 * specifying a modifier but still query the modifier associated with the 225 * resource (e.g. using gbm_bo_get_modifier()) before handing it to the 226 * framebuffer creation API (such as the DRM_IOCTL_MODE_ADDFB2 IOCTL). 227 */ 228 if (template->bind & PIPE_BIND_SCANOUT) 229 modifier = DRM_FORMAT_MOD_LINEAR; 230 231 resource->gpu = screen->gpu->resource_create_with_modifiers(screen->gpu, 232 template, 233 &modifier, 1); 234 if (!resource->gpu) 235 goto free; 236 237 /* import scanout buffers for display */ 238 if (template->bind & PIPE_BIND_SCANOUT) { 239 err = tegra_screen_import_resource(screen, resource); 240 if (err < 0) 241 goto destroy; 242 } 243 244 memcpy(&resource->base, resource->gpu, sizeof(*resource->gpu)); 245 pipe_reference_init(&resource->base.reference, 1); 246 resource->base.screen = &screen->base; 247 248 /* use private reference count for wrapped resources */ 249 resource->gpu->reference.count += 100000000; 250 resource->refcount = 100000000; 251 252 return &resource->base; 253 254destroy: 255 screen->gpu->resource_destroy(screen->gpu, resource->gpu); 256free: 257 free(resource); 258 return NULL; 259} 260 261/* XXX */ 262static struct pipe_resource * 263tegra_screen_resource_create_front(struct pipe_screen *pscreen, 264 const struct pipe_resource *template, 265 const void *map_front_private) 266{ 267 struct tegra_screen *screen = to_tegra_screen(pscreen); 268 struct pipe_resource *resource; 269 270 resource = screen->gpu->resource_create_front(screen->gpu, template, 271 map_front_private); 272 if (resource) 273 resource->screen = pscreen; 274 275 return resource; 276} 277 278static struct pipe_resource * 279tegra_screen_resource_from_handle(struct pipe_screen *pscreen, 280 const struct pipe_resource *template, 281 struct winsys_handle *handle, 282 unsigned usage) 283{ 284 struct tegra_screen *screen = to_tegra_screen(pscreen); 285 struct tegra_resource *resource; 286 287 resource = calloc(1, sizeof(*resource)); 288 if (!resource) 289 return NULL; 290 291 resource->gpu = screen->gpu->resource_from_handle(screen->gpu, template, 292 handle, usage); 293 if (!resource->gpu) { 294 free(resource); 295 return NULL; 296 } 297 298 memcpy(&resource->base, resource->gpu, sizeof(*resource->gpu)); 299 pipe_reference_init(&resource->base.reference, 1); 300 resource->base.screen = &screen->base; 301 302 return &resource->base; 303} 304 305/* XXX */ 306static struct pipe_resource * 307tegra_screen_resource_from_user_memory(struct pipe_screen *pscreen, 308 const struct pipe_resource *template, 309 void *buffer) 310{ 311 struct tegra_screen *screen = to_tegra_screen(pscreen); 312 struct pipe_resource *resource; 313 314 resource = screen->gpu->resource_from_user_memory(screen->gpu, template, 315 buffer); 316 if (resource) 317 resource->screen = pscreen; 318 319 return resource; 320} 321 322static bool 323tegra_screen_resource_get_handle(struct pipe_screen *pscreen, 324 struct pipe_context *pcontext, 325 struct pipe_resource *presource, 326 struct winsys_handle *handle, 327 unsigned usage) 328{ 329 struct tegra_resource *resource = to_tegra_resource(presource); 330 struct tegra_context *context = to_tegra_context(pcontext); 331 struct tegra_screen *screen = to_tegra_screen(pscreen); 332 bool ret = true; 333 334 /* 335 * Assume that KMS handles for scanout resources will only ever be used 336 * to pass buffers into Tegra DRM for display. In all other cases, return 337 * the Nouveau handle, assuming they will be used for sharing in DRI2/3. 338 */ 339 if (handle->type == WINSYS_HANDLE_TYPE_KMS && 340 presource->bind & PIPE_BIND_SCANOUT) { 341 handle->modifier = resource->modifier; 342 handle->handle = resource->handle; 343 handle->stride = resource->stride; 344 } else { 345 ret = screen->gpu->resource_get_handle(screen->gpu, 346 context ? context->gpu : NULL, 347 resource->gpu, handle, usage); 348 } 349 350 return ret; 351} 352 353static void 354tegra_screen_resource_destroy(struct pipe_screen *pscreen, 355 struct pipe_resource *presource) 356{ 357 struct tegra_resource *resource = to_tegra_resource(presource); 358 359 /* adjust private reference count */ 360 p_atomic_add(&resource->gpu->reference.count, -resource->refcount); 361 pipe_resource_reference(&resource->gpu, NULL); 362 free(resource); 363} 364 365static void 366tegra_screen_flush_frontbuffer(struct pipe_screen *pscreen, 367 struct pipe_context *pcontext, 368 struct pipe_resource *resource, 369 unsigned int level, 370 unsigned int layer, 371 void *winsys_drawable_handle, 372 struct pipe_box *box) 373{ 374 struct tegra_screen *screen = to_tegra_screen(pscreen); 375 struct tegra_context *context = to_tegra_context(pcontext); 376 377 screen->gpu->flush_frontbuffer(screen->gpu, 378 context ? context->gpu : NULL, 379 resource, level, layer, 380 winsys_drawable_handle, box); 381} 382 383static void 384tegra_screen_fence_reference(struct pipe_screen *pscreen, 385 struct pipe_fence_handle **ptr, 386 struct pipe_fence_handle *fence) 387{ 388 struct tegra_screen *screen = to_tegra_screen(pscreen); 389 390 screen->gpu->fence_reference(screen->gpu, ptr, fence); 391} 392 393static bool 394tegra_screen_fence_finish(struct pipe_screen *pscreen, 395 struct pipe_context *pcontext, 396 struct pipe_fence_handle *fence, 397 uint64_t timeout) 398{ 399 struct tegra_context *context = to_tegra_context(pcontext); 400 struct tegra_screen *screen = to_tegra_screen(pscreen); 401 402 return screen->gpu->fence_finish(screen->gpu, 403 context ? context->gpu : NULL, 404 fence, timeout); 405} 406 407static int 408tegra_screen_fence_get_fd(struct pipe_screen *pscreen, 409 struct pipe_fence_handle *fence) 410{ 411 struct tegra_screen *screen = to_tegra_screen(pscreen); 412 413 return screen->gpu->fence_get_fd(screen->gpu, fence); 414} 415 416static int 417tegra_screen_get_driver_query_info(struct pipe_screen *pscreen, 418 unsigned int index, 419 struct pipe_driver_query_info *info) 420{ 421 struct tegra_screen *screen = to_tegra_screen(pscreen); 422 423 return screen->gpu->get_driver_query_info(screen->gpu, index, info); 424} 425 426static int 427tegra_screen_get_driver_query_group_info(struct pipe_screen *pscreen, 428 unsigned int index, 429 struct pipe_driver_query_group_info *info) 430{ 431 struct tegra_screen *screen = to_tegra_screen(pscreen); 432 433 return screen->gpu->get_driver_query_group_info(screen->gpu, index, info); 434} 435 436static void 437tegra_screen_query_memory_info(struct pipe_screen *pscreen, 438 struct pipe_memory_info *info) 439{ 440 struct tegra_screen *screen = to_tegra_screen(pscreen); 441 442 screen->gpu->query_memory_info(screen->gpu, info); 443} 444 445static const void * 446tegra_screen_get_compiler_options(struct pipe_screen *pscreen, 447 enum pipe_shader_ir ir, 448 unsigned int shader) 449{ 450 struct tegra_screen *screen = to_tegra_screen(pscreen); 451 const void *options = NULL; 452 453 if (screen->gpu->get_compiler_options) 454 options = screen->gpu->get_compiler_options(screen->gpu, ir, shader); 455 456 return options; 457} 458 459static struct disk_cache * 460tegra_screen_get_disk_shader_cache(struct pipe_screen *pscreen) 461{ 462 struct tegra_screen *screen = to_tegra_screen(pscreen); 463 464 return screen->gpu->get_disk_shader_cache(screen->gpu); 465} 466 467static struct pipe_resource * 468tegra_screen_resource_create_with_modifiers(struct pipe_screen *pscreen, 469 const struct pipe_resource *template, 470 const uint64_t *modifiers, 471 int count) 472{ 473 struct tegra_screen *screen = to_tegra_screen(pscreen); 474 struct pipe_resource tmpl = *template; 475 struct tegra_resource *resource; 476 int err; 477 478 resource = calloc(1, sizeof(*resource)); 479 if (!resource) 480 return NULL; 481 482 /* 483 * Assume that resources created with modifiers will always be used for 484 * scanout. This is necessary because some of the APIs that are used to 485 * create resources with modifiers (e.g. gbm_bo_create_with_modifiers()) 486 * can't pass along usage information. Adding that capability might be 487 * worth adding to remove this ambiguity. Not all future use-cases that 488 * involve modifiers may always be targetting scanout hardware. 489 */ 490 tmpl.bind |= PIPE_BIND_SCANOUT; 491 492 resource->gpu = screen->gpu->resource_create_with_modifiers(screen->gpu, 493 &tmpl, 494 modifiers, 495 count); 496 if (!resource->gpu) 497 goto free; 498 499 err = tegra_screen_import_resource(screen, resource); 500 if (err < 0) 501 goto destroy; 502 503 memcpy(&resource->base, resource->gpu, sizeof(*resource->gpu)); 504 pipe_reference_init(&resource->base.reference, 1); 505 resource->base.screen = &screen->base; 506 507 return &resource->base; 508 509destroy: 510 screen->gpu->resource_destroy(screen->gpu, resource->gpu); 511free: 512 free(resource); 513 return NULL; 514} 515 516static void tegra_screen_query_dmabuf_modifiers(struct pipe_screen *pscreen, 517 enum pipe_format format, 518 int max, uint64_t *modifiers, 519 unsigned int *external_only, 520 int *count) 521{ 522 struct tegra_screen *screen = to_tegra_screen(pscreen); 523 524 screen->gpu->query_dmabuf_modifiers(screen->gpu, format, max, modifiers, 525 external_only, count); 526} 527 528static bool 529tegra_screen_is_dmabuf_modifier_supported(struct pipe_screen *pscreen, 530 uint64_t modifier, 531 enum pipe_format format, 532 bool *external_only) 533{ 534 struct tegra_screen *screen = to_tegra_screen(pscreen); 535 536 return screen->gpu->is_dmabuf_modifier_supported(screen->gpu, modifier, 537 format, external_only); 538} 539 540static unsigned int 541tegra_screen_get_dmabuf_modifier_planes(struct pipe_screen *pscreen, 542 uint64_t modifier, 543 enum pipe_format format) 544{ 545 struct tegra_screen *screen = to_tegra_screen(pscreen); 546 547 return screen->gpu->get_dmabuf_modifier_planes ? 548 screen->gpu->get_dmabuf_modifier_planes(screen->gpu, modifier, format) : 549 util_format_get_num_planes(format); 550} 551 552static struct pipe_memory_object * 553tegra_screen_memobj_create_from_handle(struct pipe_screen *pscreen, 554 struct winsys_handle *handle, 555 bool dedicated) 556{ 557 struct tegra_screen *screen = to_tegra_screen(pscreen); 558 559 return screen->gpu->memobj_create_from_handle(screen->gpu, handle, 560 dedicated); 561} 562 563struct pipe_screen * 564tegra_screen_create(int fd) 565{ 566 struct tegra_screen *screen; 567 568 screen = calloc(1, sizeof(*screen)); 569 if (!screen) 570 return NULL; 571 572 screen->fd = fd; 573 574 screen->gpu_fd = loader_open_render_node("nouveau"); 575 if (screen->gpu_fd < 0) { 576 if (errno != ENOENT) 577 fprintf(stderr, "failed to open GPU device: %s\n", strerror(errno)); 578 579 free(screen); 580 return NULL; 581 } 582 583 screen->gpu = nouveau_drm_screen_create(screen->gpu_fd); 584 if (!screen->gpu) { 585 fprintf(stderr, "failed to create GPU screen\n"); 586 close(screen->gpu_fd); 587 free(screen); 588 return NULL; 589 } 590 591 screen->base.destroy = tegra_screen_destroy; 592 screen->base.get_name = tegra_screen_get_name; 593 screen->base.get_vendor = tegra_screen_get_vendor; 594 screen->base.get_device_vendor = tegra_screen_get_device_vendor; 595 screen->base.get_param = tegra_screen_get_param; 596 screen->base.get_paramf = tegra_screen_get_paramf; 597 screen->base.get_shader_param = tegra_screen_get_shader_param; 598 screen->base.get_video_param = tegra_screen_get_video_param; 599 screen->base.get_compute_param = tegra_screen_get_compute_param; 600 screen->base.get_timestamp = tegra_screen_get_timestamp; 601 screen->base.context_create = tegra_screen_context_create; 602 screen->base.is_format_supported = tegra_screen_is_format_supported; 603 screen->base.is_video_format_supported = tegra_screen_is_video_format_supported; 604 605 /* allow fallback implementation if GPU driver doesn't implement it */ 606 if (screen->gpu->can_create_resource) 607 screen->base.can_create_resource = tegra_screen_can_create_resource; 608 609 screen->base.resource_create = tegra_screen_resource_create; 610 screen->base.resource_create_front = tegra_screen_resource_create_front; 611 screen->base.resource_from_handle = tegra_screen_resource_from_handle; 612 screen->base.resource_from_user_memory = tegra_screen_resource_from_user_memory; 613 screen->base.resource_get_handle = tegra_screen_resource_get_handle; 614 screen->base.resource_destroy = tegra_screen_resource_destroy; 615 616 screen->base.flush_frontbuffer = tegra_screen_flush_frontbuffer; 617 screen->base.fence_reference = tegra_screen_fence_reference; 618 screen->base.fence_finish = tegra_screen_fence_finish; 619 screen->base.fence_get_fd = tegra_screen_fence_get_fd; 620 621 screen->base.get_driver_query_info = tegra_screen_get_driver_query_info; 622 screen->base.get_driver_query_group_info = tegra_screen_get_driver_query_group_info; 623 screen->base.query_memory_info = tegra_screen_query_memory_info; 624 625 screen->base.get_compiler_options = tegra_screen_get_compiler_options; 626 screen->base.get_disk_shader_cache = tegra_screen_get_disk_shader_cache; 627 628 screen->base.resource_create_with_modifiers = tegra_screen_resource_create_with_modifiers; 629 screen->base.query_dmabuf_modifiers = tegra_screen_query_dmabuf_modifiers; 630 screen->base.is_dmabuf_modifier_supported = tegra_screen_is_dmabuf_modifier_supported; 631 screen->base.get_dmabuf_modifier_planes = tegra_screen_get_dmabuf_modifier_planes; 632 screen->base.memobj_create_from_handle = tegra_screen_memobj_create_from_handle; 633 634 return &screen->base; 635} 636