1 /************************************************************************** 2 * 3 * Copyright 2007 VMware, Inc. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * 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 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28 #ifndef U_INLINES_H 29 #define U_INLINES_H 30 31 #include "pipe/p_context.h" 32 #include "pipe/p_defines.h" 33 #include "pipe/p_shader_tokens.h" 34 #include "pipe/p_state.h" 35 #include "pipe/p_screen.h" 36 #include "util/u_debug.h" 37 #include "util/u_debug_describe.h" 38 #include "util/u_debug_refcnt.h" 39 #include "util/u_atomic.h" 40 #include "util/u_box.h" 41 #include "util/u_math.h" 42 43 44 #ifdef __cplusplus 45 extern "C" { 46 #endif 47 48 49 /* 50 * Reference counting helper functions. 51 */ 52 53 54 static inline void 55 pipe_reference_init(struct pipe_reference *reference, unsigned count) 56 { 57 p_atomic_set(&reference->count, count); 58 } 59 60 static inline boolean 61 pipe_is_referenced(struct pipe_reference *reference) 62 { 63 return p_atomic_read(&reference->count) != 0; 64 } 65 66 /** 67 * Update reference counting. 68 * The old thing pointed to, if any, will be unreferenced. 69 * Both 'ptr' and 'reference' may be NULL. 70 * \return TRUE if the object's refcount hits zero and should be destroyed. 71 */ 72 static inline boolean 73 pipe_reference_described(struct pipe_reference *ptr, 74 struct pipe_reference *reference, 75 debug_reference_descriptor get_desc) 76 { 77 boolean destroy = FALSE; 78 79 if(ptr != reference) { 80 /* bump the reference.count first */ 81 if (reference) { 82 assert(pipe_is_referenced(reference)); 83 p_atomic_inc(&reference->count); 84 debug_reference(reference, get_desc, 1); 85 } 86 87 if (ptr) { 88 assert(pipe_is_referenced(ptr)); 89 if (p_atomic_dec_zero(&ptr->count)) { 90 destroy = TRUE; 91 } 92 debug_reference(ptr, get_desc, -1); 93 } 94 } 95 96 return destroy; 97 } 98 99 static inline boolean 100 pipe_reference(struct pipe_reference *ptr, struct pipe_reference *reference) 101 { 102 return pipe_reference_described(ptr, reference, 103 (debug_reference_descriptor)debug_describe_reference); 104 } 105 106 static inline void 107 pipe_surface_reference(struct pipe_surface **ptr, struct pipe_surface *surf) 108 { 109 struct pipe_surface *old_surf = *ptr; 110 111 if (pipe_reference_described(&(*ptr)->reference, &surf->reference, 112 (debug_reference_descriptor)debug_describe_surface)) 113 old_surf->context->surface_destroy(old_surf->context, old_surf); 114 *ptr = surf; 115 } 116 117 /** 118 * Similar to pipe_surface_reference() but always set the pointer to NULL 119 * and pass in an explicit context. The explicit context avoids the problem 120 * of using a deleted context's surface_destroy() method when freeing a surface 121 * that's shared by multiple contexts. 122 */ 123 static inline void 124 pipe_surface_release(struct pipe_context *pipe, struct pipe_surface **ptr) 125 { 126 if (pipe_reference_described(&(*ptr)->reference, NULL, 127 (debug_reference_descriptor)debug_describe_surface)) 128 pipe->surface_destroy(pipe, *ptr); 129 *ptr = NULL; 130 } 131 132 133 static inline void 134 pipe_resource_reference(struct pipe_resource **ptr, struct pipe_resource *tex) 135 { 136 struct pipe_resource *old_tex = *ptr; 137 138 if (pipe_reference_described(&(*ptr)->reference, &tex->reference, 139 (debug_reference_descriptor)debug_describe_resource)) { 140 pipe_resource_reference(&old_tex->next, NULL); 141 old_tex->screen->resource_destroy(old_tex->screen, old_tex); 142 } 143 *ptr = tex; 144 } 145 146 static inline void 147 pipe_sampler_view_reference(struct pipe_sampler_view **ptr, struct pipe_sampler_view *view) 148 { 149 struct pipe_sampler_view *old_view = *ptr; 150 151 if (pipe_reference_described(&(*ptr)->reference, &view->reference, 152 (debug_reference_descriptor)debug_describe_sampler_view)) 153 old_view->context->sampler_view_destroy(old_view->context, old_view); 154 *ptr = view; 155 } 156 157 /** 158 * Similar to pipe_sampler_view_reference() but always set the pointer to 159 * NULL and pass in an explicit context. Passing an explicit context is a 160 * work-around for fixing a dangling context pointer problem when textures 161 * are shared by multiple contexts. XXX fix this someday. 162 */ 163 static inline void 164 pipe_sampler_view_release(struct pipe_context *ctx, 165 struct pipe_sampler_view **ptr) 166 { 167 struct pipe_sampler_view *old_view = *ptr; 168 if (*ptr && (*ptr)->context != ctx) { 169 debug_printf_once(("context mis-match in pipe_sampler_view_release()\n")); 170 } 171 if (pipe_reference_described(&(*ptr)->reference, NULL, 172 (debug_reference_descriptor)debug_describe_sampler_view)) { 173 ctx->sampler_view_destroy(ctx, old_view); 174 } 175 *ptr = NULL; 176 } 177 178 static inline void 179 pipe_so_target_reference(struct pipe_stream_output_target **ptr, 180 struct pipe_stream_output_target *target) 181 { 182 struct pipe_stream_output_target *old = *ptr; 183 184 if (pipe_reference_described(&(*ptr)->reference, &target->reference, 185 (debug_reference_descriptor)debug_describe_so_target)) 186 old->context->stream_output_target_destroy(old->context, old); 187 *ptr = target; 188 } 189 190 static inline void 191 pipe_surface_reset(struct pipe_context *ctx, struct pipe_surface* ps, 192 struct pipe_resource *pt, unsigned level, unsigned layer) 193 { 194 pipe_resource_reference(&ps->texture, pt); 195 ps->format = pt->format; 196 ps->width = u_minify(pt->width0, level); 197 ps->height = u_minify(pt->height0, level); 198 ps->u.tex.level = level; 199 ps->u.tex.first_layer = ps->u.tex.last_layer = layer; 200 ps->context = ctx; 201 } 202 203 static inline void 204 pipe_surface_init(struct pipe_context *ctx, struct pipe_surface* ps, 205 struct pipe_resource *pt, unsigned level, unsigned layer) 206 { 207 ps->texture = 0; 208 pipe_reference_init(&ps->reference, 1); 209 pipe_surface_reset(ctx, ps, pt, level, layer); 210 } 211 212 /* Return true if the surfaces are equal. */ 213 static inline boolean 214 pipe_surface_equal(struct pipe_surface *s1, struct pipe_surface *s2) 215 { 216 return s1->texture == s2->texture && 217 s1->format == s2->format && 218 (s1->texture->target != PIPE_BUFFER || 219 (s1->u.buf.first_element == s2->u.buf.first_element && 220 s1->u.buf.last_element == s2->u.buf.last_element)) && 221 (s1->texture->target == PIPE_BUFFER || 222 (s1->u.tex.level == s2->u.tex.level && 223 s1->u.tex.first_layer == s2->u.tex.first_layer && 224 s1->u.tex.last_layer == s2->u.tex.last_layer)); 225 } 226 227 /* 228 * Convenience wrappers for screen buffer functions. 229 */ 230 231 232 /** 233 * Create a new resource. 234 * \param bind bitmask of PIPE_BIND_x flags 235 * \param usage a PIPE_USAGE_x value 236 */ 237 static inline struct pipe_resource * 238 pipe_buffer_create( struct pipe_screen *screen, 239 unsigned bind, 240 enum pipe_resource_usage usage, 241 unsigned size ) 242 { 243 struct pipe_resource buffer; 244 memset(&buffer, 0, sizeof buffer); 245 buffer.target = PIPE_BUFFER; 246 buffer.format = PIPE_FORMAT_R8_UNORM; /* want TYPELESS or similar */ 247 buffer.bind = bind; 248 buffer.usage = usage; 249 buffer.flags = 0; 250 buffer.width0 = size; 251 buffer.height0 = 1; 252 buffer.depth0 = 1; 253 buffer.array_size = 1; 254 return screen->resource_create(screen, &buffer); 255 } 256 257 258 /** 259 * Map a range of a resource. 260 * \param offset start of region, in bytes 261 * \param length size of region, in bytes 262 * \param access bitmask of PIPE_TRANSFER_x flags 263 * \param transfer returns a transfer object 264 */ 265 static inline void * 266 pipe_buffer_map_range(struct pipe_context *pipe, 267 struct pipe_resource *buffer, 268 unsigned offset, 269 unsigned length, 270 unsigned access, 271 struct pipe_transfer **transfer) 272 { 273 struct pipe_box box; 274 void *map; 275 276 assert(offset < buffer->width0); 277 assert(offset + length <= buffer->width0); 278 assert(length); 279 280 u_box_1d(offset, length, &box); 281 282 map = pipe->transfer_map(pipe, buffer, 0, access, &box, transfer); 283 if (!map) { 284 return NULL; 285 } 286 287 return map; 288 } 289 290 291 /** 292 * Map whole resource. 293 * \param access bitmask of PIPE_TRANSFER_x flags 294 * \param transfer returns a transfer object 295 */ 296 static inline void * 297 pipe_buffer_map(struct pipe_context *pipe, 298 struct pipe_resource *buffer, 299 unsigned access, 300 struct pipe_transfer **transfer) 301 { 302 return pipe_buffer_map_range(pipe, buffer, 0, buffer->width0, access, transfer); 303 } 304 305 306 static inline void 307 pipe_buffer_unmap(struct pipe_context *pipe, 308 struct pipe_transfer *transfer) 309 { 310 pipe->transfer_unmap(pipe, transfer); 311 } 312 313 static inline void 314 pipe_buffer_flush_mapped_range(struct pipe_context *pipe, 315 struct pipe_transfer *transfer, 316 unsigned offset, 317 unsigned length) 318 { 319 struct pipe_box box; 320 int transfer_offset; 321 322 assert(length); 323 assert(transfer->box.x <= (int) offset); 324 assert((int) (offset + length) <= transfer->box.x + transfer->box.width); 325 326 /* Match old screen->buffer_flush_mapped_range() behaviour, where 327 * offset parameter is relative to the start of the buffer, not the 328 * mapped range. 329 */ 330 transfer_offset = offset - transfer->box.x; 331 332 u_box_1d(transfer_offset, length, &box); 333 334 pipe->transfer_flush_region(pipe, transfer, &box); 335 } 336 337 static inline void 338 pipe_buffer_write(struct pipe_context *pipe, 339 struct pipe_resource *buf, 340 unsigned offset, 341 unsigned size, 342 const void *data) 343 { 344 /* Don't set any other usage bits. Drivers should derive them. */ 345 pipe->buffer_subdata(pipe, buf, PIPE_TRANSFER_WRITE, offset, size, data); 346 } 347 348 /** 349 * Special case for writing non-overlapping ranges. 350 * 351 * We can avoid GPU/CPU synchronization when writing range that has never 352 * been written before. 353 */ 354 static inline void 355 pipe_buffer_write_nooverlap(struct pipe_context *pipe, 356 struct pipe_resource *buf, 357 unsigned offset, unsigned size, 358 const void *data) 359 { 360 pipe->buffer_subdata(pipe, buf, 361 (PIPE_TRANSFER_WRITE | 362 PIPE_TRANSFER_UNSYNCHRONIZED), 363 offset, size, data); 364 } 365 366 367 /** 368 * Create a new resource and immediately put data into it 369 * \param bind bitmask of PIPE_BIND_x flags 370 * \param usage bitmask of PIPE_USAGE_x flags 371 */ 372 static inline struct pipe_resource * 373 pipe_buffer_create_with_data(struct pipe_context *pipe, 374 unsigned bind, 375 enum pipe_resource_usage usage, 376 unsigned size, 377 const void *ptr) 378 { 379 struct pipe_resource *res = pipe_buffer_create(pipe->screen, 380 bind, usage, size); 381 pipe_buffer_write_nooverlap(pipe, res, 0, size, ptr); 382 return res; 383 } 384 385 static inline void 386 pipe_buffer_read(struct pipe_context *pipe, 387 struct pipe_resource *buf, 388 unsigned offset, 389 unsigned size, 390 void *data) 391 { 392 struct pipe_transfer *src_transfer; 393 ubyte *map; 394 395 map = (ubyte *) pipe_buffer_map_range(pipe, 396 buf, 397 offset, size, 398 PIPE_TRANSFER_READ, 399 &src_transfer); 400 if (!map) 401 return; 402 403 memcpy(data, map, size); 404 pipe_buffer_unmap(pipe, src_transfer); 405 } 406 407 408 /** 409 * Map a resource for reading/writing. 410 * \param access bitmask of PIPE_TRANSFER_x flags 411 */ 412 static inline void * 413 pipe_transfer_map(struct pipe_context *context, 414 struct pipe_resource *resource, 415 unsigned level, unsigned layer, 416 unsigned access, 417 unsigned x, unsigned y, 418 unsigned w, unsigned h, 419 struct pipe_transfer **transfer) 420 { 421 struct pipe_box box; 422 u_box_2d_zslice(x, y, layer, w, h, &box); 423 return context->transfer_map(context, 424 resource, 425 level, 426 access, 427 &box, transfer); 428 } 429 430 431 /** 432 * Map a 3D (texture) resource for reading/writing. 433 * \param access bitmask of PIPE_TRANSFER_x flags 434 */ 435 static inline void * 436 pipe_transfer_map_3d(struct pipe_context *context, 437 struct pipe_resource *resource, 438 unsigned level, 439 unsigned access, 440 unsigned x, unsigned y, unsigned z, 441 unsigned w, unsigned h, unsigned d, 442 struct pipe_transfer **transfer) 443 { 444 struct pipe_box box; 445 u_box_3d(x, y, z, w, h, d, &box); 446 return context->transfer_map(context, 447 resource, 448 level, 449 access, 450 &box, transfer); 451 } 452 453 static inline void 454 pipe_transfer_unmap( struct pipe_context *context, 455 struct pipe_transfer *transfer ) 456 { 457 context->transfer_unmap( context, transfer ); 458 } 459 460 static inline void 461 pipe_set_constant_buffer(struct pipe_context *pipe, uint shader, uint index, 462 struct pipe_resource *buf) 463 { 464 if (buf) { 465 struct pipe_constant_buffer cb; 466 cb.buffer = buf; 467 cb.buffer_offset = 0; 468 cb.buffer_size = buf->width0; 469 cb.user_buffer = NULL; 470 pipe->set_constant_buffer(pipe, shader, index, &cb); 471 } else { 472 pipe->set_constant_buffer(pipe, shader, index, NULL); 473 } 474 } 475 476 477 /** 478 * Get the polygon offset enable/disable flag for the given polygon fill mode. 479 * \param fill_mode one of PIPE_POLYGON_MODE_POINT/LINE/FILL 480 */ 481 static inline boolean 482 util_get_offset(const struct pipe_rasterizer_state *templ, 483 unsigned fill_mode) 484 { 485 switch(fill_mode) { 486 case PIPE_POLYGON_MODE_POINT: 487 return templ->offset_point; 488 case PIPE_POLYGON_MODE_LINE: 489 return templ->offset_line; 490 case PIPE_POLYGON_MODE_FILL: 491 return templ->offset_tri; 492 default: 493 assert(0); 494 return FALSE; 495 } 496 } 497 498 static inline float 499 util_get_min_point_size(const struct pipe_rasterizer_state *state) 500 { 501 /* The point size should be clamped to this value at the rasterizer stage. 502 */ 503 return !state->point_quad_rasterization && 504 !state->point_smooth && 505 !state->multisample ? 1.0f : 0.0f; 506 } 507 508 static inline void 509 util_query_clear_result(union pipe_query_result *result, unsigned type) 510 { 511 switch (type) { 512 case PIPE_QUERY_OCCLUSION_PREDICATE: 513 case PIPE_QUERY_SO_OVERFLOW_PREDICATE: 514 case PIPE_QUERY_GPU_FINISHED: 515 result->b = FALSE; 516 break; 517 case PIPE_QUERY_OCCLUSION_COUNTER: 518 case PIPE_QUERY_TIMESTAMP: 519 case PIPE_QUERY_TIME_ELAPSED: 520 case PIPE_QUERY_PRIMITIVES_GENERATED: 521 case PIPE_QUERY_PRIMITIVES_EMITTED: 522 result->u64 = 0; 523 break; 524 case PIPE_QUERY_SO_STATISTICS: 525 memset(&result->so_statistics, 0, sizeof(result->so_statistics)); 526 break; 527 case PIPE_QUERY_TIMESTAMP_DISJOINT: 528 memset(&result->timestamp_disjoint, 0, sizeof(result->timestamp_disjoint)); 529 break; 530 case PIPE_QUERY_PIPELINE_STATISTICS: 531 memset(&result->pipeline_statistics, 0, sizeof(result->pipeline_statistics)); 532 break; 533 default: 534 memset(result, 0, sizeof(*result)); 535 } 536 } 537 538 /** Convert PIPE_TEXTURE_x to TGSI_TEXTURE_x */ 539 static inline unsigned 540 util_pipe_tex_to_tgsi_tex(enum pipe_texture_target pipe_tex_target, 541 unsigned nr_samples) 542 { 543 switch (pipe_tex_target) { 544 case PIPE_BUFFER: 545 return TGSI_TEXTURE_BUFFER; 546 547 case PIPE_TEXTURE_1D: 548 assert(nr_samples <= 1); 549 return TGSI_TEXTURE_1D; 550 551 case PIPE_TEXTURE_2D: 552 return nr_samples > 1 ? TGSI_TEXTURE_2D_MSAA : TGSI_TEXTURE_2D; 553 554 case PIPE_TEXTURE_RECT: 555 assert(nr_samples <= 1); 556 return TGSI_TEXTURE_RECT; 557 558 case PIPE_TEXTURE_3D: 559 assert(nr_samples <= 1); 560 return TGSI_TEXTURE_3D; 561 562 case PIPE_TEXTURE_CUBE: 563 assert(nr_samples <= 1); 564 return TGSI_TEXTURE_CUBE; 565 566 case PIPE_TEXTURE_1D_ARRAY: 567 assert(nr_samples <= 1); 568 return TGSI_TEXTURE_1D_ARRAY; 569 570 case PIPE_TEXTURE_2D_ARRAY: 571 return nr_samples > 1 ? TGSI_TEXTURE_2D_ARRAY_MSAA : 572 TGSI_TEXTURE_2D_ARRAY; 573 574 case PIPE_TEXTURE_CUBE_ARRAY: 575 return TGSI_TEXTURE_CUBE_ARRAY; 576 577 default: 578 assert(0 && "unexpected texture target"); 579 return TGSI_TEXTURE_UNKNOWN; 580 } 581 } 582 583 584 static inline void 585 util_copy_constant_buffer(struct pipe_constant_buffer *dst, 586 const struct pipe_constant_buffer *src) 587 { 588 if (src) { 589 pipe_resource_reference(&dst->buffer, src->buffer); 590 dst->buffer_offset = src->buffer_offset; 591 dst->buffer_size = src->buffer_size; 592 dst->user_buffer = src->user_buffer; 593 } 594 else { 595 pipe_resource_reference(&dst->buffer, NULL); 596 dst->buffer_offset = 0; 597 dst->buffer_size = 0; 598 dst->user_buffer = NULL; 599 } 600 } 601 602 static inline void 603 util_copy_image_view(struct pipe_image_view *dst, 604 const struct pipe_image_view *src) 605 { 606 if (src) { 607 pipe_resource_reference(&dst->resource, src->resource); 608 dst->format = src->format; 609 dst->access = src->access; 610 dst->u = src->u; 611 } else { 612 pipe_resource_reference(&dst->resource, NULL); 613 dst->format = PIPE_FORMAT_NONE; 614 dst->access = 0; 615 memset(&dst->u, 0, sizeof(dst->u)); 616 } 617 } 618 619 static inline unsigned 620 util_max_layer(const struct pipe_resource *r, unsigned level) 621 { 622 switch (r->target) { 623 case PIPE_TEXTURE_3D: 624 return u_minify(r->depth0, level) - 1; 625 case PIPE_TEXTURE_CUBE: 626 assert(r->array_size == 6); 627 /* fall-through */ 628 case PIPE_TEXTURE_1D_ARRAY: 629 case PIPE_TEXTURE_2D_ARRAY: 630 case PIPE_TEXTURE_CUBE_ARRAY: 631 return r->array_size - 1; 632 default: 633 return 0; 634 } 635 } 636 637 static inline bool 638 util_texrange_covers_whole_level(const struct pipe_resource *tex, 639 unsigned level, unsigned x, unsigned y, 640 unsigned z, unsigned width, 641 unsigned height, unsigned depth) 642 { 643 return x == 0 && y == 0 && z == 0 && 644 width == u_minify(tex->width0, level) && 645 height == u_minify(tex->height0, level) && 646 depth == util_max_layer(tex, level) + 1; 647 } 648 649 #ifdef __cplusplus 650 } 651 #endif 652 653 #endif /* U_INLINES_H */ 654