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