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