1 /********************************************************** 2 * Copyright 2009-2011 VMware, Inc. All rights reserved. 3 * 4 * Permission is hereby granted, free of charge, to any person 5 * obtaining a copy of this software and associated documentation 6 * files (the "Software"), to deal in the Software without 7 * restriction, including without limitation the rights to use, copy, 8 * modify, merge, publish, distribute, sublicense, and/or sell copies 9 * of the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be 13 * included in all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 * 24 ********************************************************* 25 * Authors: 26 * Thomas Hellstrom <thellstrom-at-vmware-dot-com> 27 */ 28 29 #include <unistd.h> 30 #include <fcntl.h> 31 #include "xa_tracker.h" 32 #include "xa_priv.h" 33 #include "pipe/p_state.h" 34 #include "pipe/p_format.h" 35 #include "pipe-loader/pipe_loader.h" 36 #include "state_tracker/drm_driver.h" 37 #include "util/u_inlines.h" 38 39 /* 40 * format_map [xa_surface_type][first..last in list]. 41 * Needs to be updated when enum xa_formats is updated. 42 */ 43 44 static const enum xa_formats preferred_a[] = { xa_format_a8 }; 45 46 static const enum xa_formats preferred_argb[] = 47 { xa_format_a8r8g8b8, xa_format_x8r8g8b8, xa_format_r5g6b5, 48 xa_format_x1r5g5b5 49 }; 50 static const enum xa_formats preferred_z[] = 51 { xa_format_z32, xa_format_z24, xa_format_z16 }; 52 static const enum xa_formats preferred_sz[] = 53 { xa_format_x8z24, xa_format_s8z24 }; 54 static const enum xa_formats preferred_zs[] = 55 { xa_format_z24x8, xa_format_z24s8 }; 56 static const enum xa_formats preferred_yuv[] = { xa_format_yuv8 }; 57 58 static const enum xa_formats *preferred[] = 59 { NULL, preferred_a, preferred_argb, NULL, NULL, 60 preferred_z, preferred_zs, preferred_sz, preferred_yuv 61 }; 62 63 static const unsigned int num_preferred[] = { 0, 64 sizeof(preferred_a) / sizeof(enum xa_formats), 65 sizeof(preferred_argb) / sizeof(enum xa_formats), 66 0, 67 0, 68 sizeof(preferred_z) / sizeof(enum xa_formats), 69 sizeof(preferred_zs) / sizeof(enum xa_formats), 70 sizeof(preferred_sz) / sizeof(enum xa_formats), 71 sizeof(preferred_yuv) / sizeof(enum xa_formats) 72 }; 73 74 static const unsigned int stype_bind[XA_LAST_SURFACE_TYPE] = { 0, 75 PIPE_BIND_SAMPLER_VIEW, 76 PIPE_BIND_SAMPLER_VIEW, 77 PIPE_BIND_SAMPLER_VIEW, 78 PIPE_BIND_SAMPLER_VIEW, 79 PIPE_BIND_DEPTH_STENCIL, 80 PIPE_BIND_DEPTH_STENCIL, 81 PIPE_BIND_DEPTH_STENCIL, 82 PIPE_BIND_SAMPLER_VIEW 83 }; 84 85 static struct xa_format_descriptor 86 xa_get_pipe_format(struct xa_tracker *xa, enum xa_formats xa_format) 87 { 88 struct xa_format_descriptor fdesc; 89 90 fdesc.xa_format = xa_format; 91 92 switch (xa_format) { 93 case xa_format_a8r8g8b8: 94 fdesc.format = PIPE_FORMAT_B8G8R8A8_UNORM; 95 break; 96 case xa_format_x8r8g8b8: 97 fdesc.format = PIPE_FORMAT_B8G8R8X8_UNORM; 98 break; 99 case xa_format_r5g6b5: 100 fdesc.format = PIPE_FORMAT_B5G6R5_UNORM; 101 break; 102 case xa_format_x1r5g5b5: 103 fdesc.format = PIPE_FORMAT_B5G5R5A1_UNORM; 104 break; 105 case xa_format_a8: 106 if (xa->screen->is_format_supported(xa->screen, PIPE_FORMAT_R8_UNORM, 107 PIPE_TEXTURE_2D, 0, 108 stype_bind[xa_type_a] | 109 PIPE_BIND_RENDER_TARGET)) 110 fdesc.format = PIPE_FORMAT_R8_UNORM; 111 else 112 fdesc.format = PIPE_FORMAT_L8_UNORM; 113 break; 114 case xa_format_z24: 115 fdesc.format = PIPE_FORMAT_Z24X8_UNORM; 116 break; 117 case xa_format_z16: 118 fdesc.format = PIPE_FORMAT_Z16_UNORM; 119 break; 120 case xa_format_z32: 121 fdesc.format = PIPE_FORMAT_Z32_UNORM; 122 break; 123 case xa_format_x8z24: 124 fdesc.format = PIPE_FORMAT_Z24X8_UNORM; 125 break; 126 case xa_format_z24x8: 127 fdesc.format = PIPE_FORMAT_X8Z24_UNORM; 128 break; 129 case xa_format_s8z24: 130 fdesc.format = PIPE_FORMAT_Z24_UNORM_S8_UINT; 131 break; 132 case xa_format_z24s8: 133 fdesc.format = PIPE_FORMAT_S8_UINT_Z24_UNORM; 134 break; 135 case xa_format_yuv8: 136 if (xa->screen->is_format_supported(xa->screen, PIPE_FORMAT_R8_UNORM, 137 PIPE_TEXTURE_2D, 0, 138 stype_bind[xa_type_yuv_component])) 139 fdesc.format = PIPE_FORMAT_R8_UNORM; 140 else 141 fdesc.format = PIPE_FORMAT_L8_UNORM; 142 break; 143 default: 144 fdesc.xa_format = xa_format_unknown; 145 break; 146 } 147 return fdesc; 148 } 149 150 XA_EXPORT struct xa_tracker * 151 xa_tracker_create(int drm_fd) 152 { 153 struct xa_tracker *xa = calloc(1, sizeof(struct xa_tracker)); 154 enum xa_surface_type stype; 155 unsigned int num_formats; 156 int fd; 157 158 if (!xa) 159 return NULL; 160 161 if (drm_fd < 0 || (fd = fcntl(drm_fd, F_DUPFD_CLOEXEC, 3)) < 0) 162 goto out_no_fd; 163 164 if (pipe_loader_drm_probe_fd(&xa->dev, fd)) 165 xa->screen = pipe_loader_create_screen(xa->dev); 166 167 if (!xa->screen) 168 goto out_no_screen; 169 170 xa->default_ctx = xa_context_create(xa); 171 if (!xa->default_ctx) 172 goto out_no_pipe; 173 174 num_formats = 0; 175 for (stype = 0; stype < XA_LAST_SURFACE_TYPE; ++stype) 176 num_formats += num_preferred[stype]; 177 178 num_formats += 1; 179 xa->supported_formats = calloc(num_formats, sizeof(*xa->supported_formats)); 180 if (!xa->supported_formats) 181 goto out_sf_alloc_fail; 182 183 xa->supported_formats[0] = xa_format_unknown; 184 num_formats = 1; 185 memset(xa->format_map, 0, sizeof(xa->format_map)); 186 187 for (stype = 0; stype < XA_LAST_SURFACE_TYPE; ++stype) { 188 unsigned int bind = stype_bind[stype]; 189 enum xa_formats xa_format; 190 int i; 191 192 for (i = 0; i < num_preferred[stype]; ++i) { 193 xa_format = preferred[stype][i]; 194 195 struct xa_format_descriptor fdesc = 196 xa_get_pipe_format(xa, xa_format); 197 198 if (xa->screen->is_format_supported(xa->screen, fdesc.format, 199 PIPE_TEXTURE_2D, 0, bind)) { 200 if (xa->format_map[stype][0] == 0) 201 xa->format_map[stype][0] = num_formats; 202 xa->format_map[stype][1] = num_formats; 203 xa->supported_formats[num_formats++] = xa_format; 204 } 205 } 206 } 207 return xa; 208 209 out_sf_alloc_fail: 210 xa_context_destroy(xa->default_ctx); 211 out_no_pipe: 212 xa->screen->destroy(xa->screen); 213 out_no_screen: 214 if (xa->dev) 215 pipe_loader_release(&xa->dev, 1); 216 else 217 close(fd); 218 out_no_fd: 219 free(xa); 220 return NULL; 221 } 222 223 XA_EXPORT void 224 xa_tracker_destroy(struct xa_tracker *xa) 225 { 226 free(xa->supported_formats); 227 xa_context_destroy(xa->default_ctx); 228 xa->screen->destroy(xa->screen); 229 pipe_loader_release(&xa->dev, 1); 230 free(xa); 231 } 232 233 static int 234 xa_flags_compat(unsigned int old_flags, unsigned int new_flags) 235 { 236 unsigned int flag_diff = (old_flags ^ new_flags); 237 238 if (flag_diff == 0) 239 return 1; 240 241 if (flag_diff & XA_FLAG_SHARED) 242 return 0; 243 /* 244 * Don't recreate if we're dropping the render target flag. 245 */ 246 if (flag_diff & XA_FLAG_RENDER_TARGET) 247 return ((new_flags & XA_FLAG_RENDER_TARGET) == 0); 248 249 /* 250 * Don't recreate if we're dropping the scanout flag. 251 */ 252 if (flag_diff & XA_FLAG_SCANOUT) 253 return ((new_flags & XA_FLAG_SCANOUT) == 0); 254 255 /* 256 * Always recreate for unknown / unimplemented flags. 257 */ 258 return 0; 259 } 260 261 static struct xa_format_descriptor 262 xa_get_format_stype_depth(struct xa_tracker *xa, 263 enum xa_surface_type stype, unsigned int depth) 264 { 265 unsigned int i; 266 struct xa_format_descriptor fdesc; 267 int found = 0; 268 269 for (i = xa->format_map[stype][0]; i <= xa->format_map[stype][1]; ++i) { 270 fdesc = xa_get_pipe_format(xa, xa->supported_formats[i]); 271 if (fdesc.xa_format != xa_format_unknown && 272 xa_format_depth(fdesc.xa_format) == depth) { 273 found = 1; 274 break; 275 } 276 } 277 278 if (!found) 279 fdesc.xa_format = xa_format_unknown; 280 281 return fdesc; 282 } 283 284 XA_EXPORT int 285 xa_format_check_supported(struct xa_tracker *xa, 286 enum xa_formats xa_format, unsigned int flags) 287 { 288 struct xa_format_descriptor fdesc = xa_get_pipe_format(xa, xa_format); 289 unsigned int bind; 290 291 if (fdesc.xa_format == xa_format_unknown) 292 return -XA_ERR_INVAL; 293 294 bind = stype_bind[xa_format_type(fdesc.xa_format)]; 295 if (flags & XA_FLAG_SHARED) 296 bind |= PIPE_BIND_SHARED; 297 if (flags & XA_FLAG_RENDER_TARGET) 298 bind |= PIPE_BIND_RENDER_TARGET; 299 if (flags & XA_FLAG_SCANOUT) 300 bind |= PIPE_BIND_SCANOUT; 301 302 if (!xa->screen->is_format_supported(xa->screen, fdesc.format, 303 PIPE_TEXTURE_2D, 0, bind)) 304 return -XA_ERR_INVAL; 305 306 return XA_ERR_NONE; 307 } 308 309 static unsigned 310 handle_type(enum xa_handle_type type) 311 { 312 switch (type) { 313 case xa_handle_type_kms: 314 return DRM_API_HANDLE_TYPE_KMS; 315 case xa_handle_type_fd: 316 return DRM_API_HANDLE_TYPE_FD; 317 case xa_handle_type_shared: 318 default: 319 return DRM_API_HANDLE_TYPE_SHARED; 320 } 321 } 322 323 static struct xa_surface * 324 surface_create(struct xa_tracker *xa, 325 int width, 326 int height, 327 int depth, 328 enum xa_surface_type stype, 329 enum xa_formats xa_format, unsigned int flags, 330 struct winsys_handle *whandle) 331 { 332 struct pipe_resource *template; 333 struct xa_surface *srf; 334 struct xa_format_descriptor fdesc; 335 336 if (xa_format == xa_format_unknown) 337 fdesc = xa_get_format_stype_depth(xa, stype, depth); 338 else 339 fdesc = xa_get_pipe_format(xa, xa_format); 340 341 if (fdesc.xa_format == xa_format_unknown) 342 return NULL; 343 344 srf = calloc(1, sizeof(*srf)); 345 if (!srf) 346 return NULL; 347 348 template = &srf->template; 349 template->format = fdesc.format; 350 template->target = PIPE_TEXTURE_2D; 351 template->width0 = width; 352 template->height0 = height; 353 template->depth0 = 1; 354 template->array_size = 1; 355 template->last_level = 0; 356 template->bind = stype_bind[xa_format_type(fdesc.xa_format)]; 357 358 if (flags & XA_FLAG_SHARED) 359 template->bind |= PIPE_BIND_SHARED; 360 if (flags & XA_FLAG_RENDER_TARGET) 361 template->bind |= PIPE_BIND_RENDER_TARGET; 362 if (flags & XA_FLAG_SCANOUT) 363 template->bind |= PIPE_BIND_SCANOUT; 364 365 if (whandle) 366 srf->tex = xa->screen->resource_from_handle(xa->screen, template, whandle, 367 PIPE_HANDLE_USAGE_READ_WRITE); 368 else 369 srf->tex = xa->screen->resource_create(xa->screen, template); 370 if (!srf->tex) 371 goto out_no_tex; 372 373 srf->refcount = 1; 374 srf->xa = xa; 375 srf->flags = flags; 376 srf->fdesc = fdesc; 377 378 return srf; 379 out_no_tex: 380 free(srf); 381 return NULL; 382 } 383 384 385 XA_EXPORT struct xa_surface * 386 xa_surface_create(struct xa_tracker *xa, 387 int width, 388 int height, 389 int depth, 390 enum xa_surface_type stype, 391 enum xa_formats xa_format, unsigned int flags) 392 { 393 return surface_create(xa, width, height, depth, stype, xa_format, flags, NULL); 394 } 395 396 397 XA_EXPORT struct xa_surface * 398 xa_surface_from_handle(struct xa_tracker *xa, 399 int width, 400 int height, 401 int depth, 402 enum xa_surface_type stype, 403 enum xa_formats xa_format, unsigned int flags, 404 uint32_t handle, uint32_t stride) 405 { 406 return xa_surface_from_handle2(xa, width, height, depth, stype, xa_format, 407 DRM_API_HANDLE_TYPE_SHARED, flags, handle, 408 stride); 409 } 410 411 XA_EXPORT struct xa_surface * 412 xa_surface_from_handle2(struct xa_tracker *xa, 413 int width, 414 int height, 415 int depth, 416 enum xa_surface_type stype, 417 enum xa_formats xa_format, unsigned int flags, 418 enum xa_handle_type type, 419 uint32_t handle, uint32_t stride) 420 { 421 struct winsys_handle whandle; 422 memset(&whandle, 0, sizeof(whandle)); 423 whandle.type = handle_type(type); 424 whandle.handle = handle; 425 whandle.stride = stride; 426 return surface_create(xa, width, height, depth, stype, xa_format, flags, &whandle); 427 } 428 429 XA_EXPORT int 430 xa_surface_redefine(struct xa_surface *srf, 431 int width, 432 int height, 433 int depth, 434 enum xa_surface_type stype, 435 enum xa_formats xa_format, 436 unsigned int new_flags, 437 int copy_contents) 438 { 439 struct pipe_resource *template = &srf->template; 440 struct pipe_resource *texture; 441 struct pipe_box src_box; 442 struct xa_tracker *xa = srf->xa; 443 int save_width; 444 int save_height; 445 unsigned int save_format; 446 struct xa_format_descriptor fdesc; 447 448 449 if (xa_format == xa_format_unknown) 450 fdesc = xa_get_format_stype_depth(xa, stype, depth); 451 else 452 fdesc = xa_get_pipe_format(xa, xa_format); 453 454 if (width == template->width0 && height == template->height0 && 455 template->format == fdesc.format && 456 xa_flags_compat(srf->flags, new_flags)) 457 return XA_ERR_NONE; 458 459 template->bind = stype_bind[xa_format_type(fdesc.xa_format)]; 460 if (new_flags & XA_FLAG_SHARED) 461 template->bind |= PIPE_BIND_SHARED; 462 if (new_flags & XA_FLAG_RENDER_TARGET) 463 template->bind |= PIPE_BIND_RENDER_TARGET; 464 if (new_flags & XA_FLAG_SCANOUT) 465 template->bind |= PIPE_BIND_SCANOUT; 466 467 if (copy_contents) { 468 if (!xa_format_type_is_color(fdesc.xa_format) || 469 xa_format_type(fdesc.xa_format) == xa_type_a) 470 return -XA_ERR_INVAL; 471 472 if (!xa->screen->is_format_supported(xa->screen, fdesc.format, 473 PIPE_TEXTURE_2D, 0, 474 template->bind | 475 PIPE_BIND_RENDER_TARGET)) 476 return -XA_ERR_INVAL; 477 } 478 479 save_width = template->width0; 480 save_height = template->height0; 481 save_format = template->format; 482 483 template->width0 = width; 484 template->height0 = height; 485 template->format = fdesc.format; 486 487 texture = xa->screen->resource_create(xa->screen, template); 488 if (!texture) { 489 template->width0 = save_width; 490 template->height0 = save_height; 491 template->format = save_format; 492 return -XA_ERR_NORES; 493 } 494 495 if (copy_contents) { 496 struct pipe_context *pipe = xa->default_ctx->pipe; 497 498 u_box_origin_2d(xa_min(save_width, template->width0), 499 xa_min(save_height, template->height0), &src_box); 500 pipe->resource_copy_region(pipe, texture, 501 0, 0, 0, 0, srf->tex, 0, &src_box); 502 xa_context_flush(xa->default_ctx); 503 } 504 505 pipe_resource_reference(&srf->tex, texture); 506 pipe_resource_reference(&texture, NULL); 507 srf->fdesc = fdesc; 508 srf->flags = new_flags; 509 510 return XA_ERR_NONE; 511 } 512 513 XA_EXPORT struct xa_surface* 514 xa_surface_ref(struct xa_surface *srf) 515 { 516 if (srf == NULL) { 517 return NULL; 518 } 519 srf->refcount++; 520 return srf; 521 } 522 523 XA_EXPORT void 524 xa_surface_unref(struct xa_surface *srf) 525 { 526 if (srf == NULL || --srf->refcount) { 527 return; 528 } 529 pipe_resource_reference(&srf->tex, NULL); 530 free(srf); 531 } 532 533 XA_EXPORT void 534 xa_tracker_version(int *major, int *minor, int *patch) 535 { 536 *major = XA_TRACKER_VERSION_MAJOR; 537 *minor = XA_TRACKER_VERSION_MINOR; 538 *patch = XA_TRACKER_VERSION_PATCH; 539 } 540 541 XA_EXPORT int 542 xa_surface_handle(struct xa_surface *srf, 543 enum xa_handle_type type, 544 uint32_t * handle, unsigned int *stride) 545 { 546 struct winsys_handle whandle; 547 548 struct pipe_screen *screen = srf->xa->screen; 549 boolean res; 550 551 memset(&whandle, 0, sizeof(whandle)); 552 whandle.type = handle_type(type); 553 res = screen->resource_get_handle(screen, srf->xa->default_ctx->pipe, 554 srf->tex, &whandle, 555 PIPE_HANDLE_USAGE_READ_WRITE); 556 if (!res) 557 return -XA_ERR_INVAL; 558 559 *handle = whandle.handle; 560 *stride = whandle.stride; 561 562 return XA_ERR_NONE; 563 } 564 565 XA_EXPORT enum xa_formats 566 xa_surface_format(const struct xa_surface *srf) 567 { 568 return srf->fdesc.xa_format; 569 } 570