u_inlines.h revision 214b87aa0469a12ea72d624cfaee0ca46179ec5f
1/************************************************************************** 2 * 3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. 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 TUNGSTEN GRAPHICS 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_state.h" 34#include "pipe/p_screen.h" 35#include "util/u_debug.h" 36#include "util/u_debug_describe.h" 37#include "util/u_debug_refcnt.h" 38#include "util/u_atomic.h" 39#include "util/u_box.h" 40#include "util/u_math.h" 41 42 43#ifdef __cplusplus 44extern "C" { 45#endif 46 47 48/* 49 * Reference counting helper functions. 50 */ 51 52 53static INLINE void 54pipe_reference_init(struct pipe_reference *reference, unsigned count) 55{ 56 p_atomic_set(&reference->count, count); 57} 58 59static INLINE boolean 60pipe_is_referenced(struct pipe_reference *reference) 61{ 62 return p_atomic_read(&reference->count) != 0; 63} 64 65/** 66 * Update reference counting. 67 * The old thing pointed to, if any, will be unreferenced. 68 * Both 'ptr' and 'reference' may be NULL. 69 * \return TRUE if the object's refcount hits zero and should be destroyed. 70 */ 71static INLINE boolean 72pipe_reference_described(struct pipe_reference *ptr, 73 struct pipe_reference *reference, 74 debug_reference_descriptor get_desc) 75{ 76 boolean destroy = FALSE; 77 78 if(ptr != reference) { 79 /* bump the reference.count first */ 80 if (reference) { 81 assert(pipe_is_referenced(reference)); 82 p_atomic_inc(&reference->count); 83 debug_reference(reference, get_desc, 1); 84 } 85 86 if (ptr) { 87 assert(pipe_is_referenced(ptr)); 88 if (p_atomic_dec_zero(&ptr->count)) { 89 destroy = TRUE; 90 } 91 debug_reference(ptr, get_desc, -1); 92 } 93 } 94 95 return destroy; 96} 97 98static INLINE boolean 99pipe_reference(struct pipe_reference *ptr, struct pipe_reference *reference) 100{ 101 return pipe_reference_described(ptr, reference, 102 (debug_reference_descriptor)debug_describe_reference); 103} 104 105static INLINE void 106pipe_surface_reference(struct pipe_surface **ptr, struct pipe_surface *surf) 107{ 108 struct pipe_surface *old_surf = *ptr; 109 110 if (pipe_reference_described(&(*ptr)->reference, &surf->reference, 111 (debug_reference_descriptor)debug_describe_surface)) 112 old_surf->context->surface_destroy(old_surf->context, old_surf); 113 *ptr = surf; 114} 115 116static INLINE void 117pipe_resource_reference(struct pipe_resource **ptr, struct pipe_resource *tex) 118{ 119 struct pipe_resource *old_tex = *ptr; 120 121 if (pipe_reference_described(&(*ptr)->reference, &tex->reference, 122 (debug_reference_descriptor)debug_describe_resource)) 123 old_tex->screen->resource_destroy(old_tex->screen, old_tex); 124 *ptr = tex; 125} 126 127static INLINE void 128pipe_sampler_view_reference(struct pipe_sampler_view **ptr, struct pipe_sampler_view *view) 129{ 130 struct pipe_sampler_view *old_view = *ptr; 131 132 if (pipe_reference_described(&(*ptr)->reference, &view->reference, 133 (debug_reference_descriptor)debug_describe_sampler_view)) 134 old_view->context->sampler_view_destroy(old_view->context, old_view); 135 *ptr = view; 136} 137 138static INLINE void 139pipe_so_target_reference(struct pipe_stream_output_target **ptr, 140 struct pipe_stream_output_target *target) 141{ 142 struct pipe_stream_output_target *old = *ptr; 143 144 if (pipe_reference_described(&(*ptr)->reference, &target->reference, 145 (debug_reference_descriptor)debug_describe_so_target)) 146 old->context->stream_output_target_destroy(old->context, old); 147 *ptr = target; 148} 149 150static INLINE void 151pipe_surface_reset(struct pipe_context *ctx, struct pipe_surface* ps, 152 struct pipe_resource *pt, unsigned level, unsigned layer, 153 unsigned flags) 154{ 155 pipe_resource_reference(&ps->texture, pt); 156 ps->format = pt->format; 157 ps->width = u_minify(pt->width0, level); 158 ps->height = u_minify(pt->height0, level); 159 ps->usage = flags; 160 ps->u.tex.level = level; 161 ps->u.tex.first_layer = ps->u.tex.last_layer = layer; 162 ps->context = ctx; 163} 164 165static INLINE void 166pipe_surface_init(struct pipe_context *ctx, struct pipe_surface* ps, 167 struct pipe_resource *pt, unsigned level, unsigned layer, 168 unsigned flags) 169{ 170 ps->texture = 0; 171 pipe_reference_init(&ps->reference, 1); 172 pipe_surface_reset(ctx, ps, pt, level, layer, flags); 173} 174 175/* Return true if the surfaces are equal. */ 176static INLINE boolean 177pipe_surface_equal(struct pipe_surface *s1, struct pipe_surface *s2) 178{ 179 return s1->texture == s2->texture && 180 s1->format == s2->format && 181 (s1->texture->target != PIPE_BUFFER || 182 (s1->u.buf.first_element == s2->u.buf.first_element && 183 s1->u.buf.last_element == s2->u.buf.last_element)) && 184 (s1->texture->target == PIPE_BUFFER || 185 (s1->u.tex.level == s2->u.tex.level && 186 s1->u.tex.first_layer == s2->u.tex.first_layer && 187 s1->u.tex.last_layer == s2->u.tex.last_layer)); 188} 189 190/* 191 * Convenience wrappers for screen buffer functions. 192 */ 193 194static INLINE struct pipe_resource * 195pipe_buffer_create( struct pipe_screen *screen, 196 unsigned bind, 197 unsigned usage, 198 unsigned size ) 199{ 200 struct pipe_resource buffer; 201 memset(&buffer, 0, sizeof buffer); 202 buffer.target = PIPE_BUFFER; 203 buffer.format = PIPE_FORMAT_R8_UNORM; /* want TYPELESS or similar */ 204 buffer.bind = bind; 205 buffer.usage = usage; 206 buffer.flags = 0; 207 buffer.width0 = size; 208 buffer.height0 = 1; 209 buffer.depth0 = 1; 210 buffer.array_size = 1; 211 return screen->resource_create(screen, &buffer); 212} 213 214 215static INLINE struct pipe_resource * 216pipe_user_buffer_create( struct pipe_screen *screen, void *ptr, unsigned size, 217 unsigned usage ) 218{ 219 return screen->user_buffer_create(screen, ptr, size, usage); 220} 221 222static INLINE void * 223pipe_buffer_map_range(struct pipe_context *pipe, 224 struct pipe_resource *buffer, 225 unsigned offset, 226 unsigned length, 227 unsigned usage, 228 struct pipe_transfer **transfer) 229{ 230 struct pipe_box box; 231 void *map; 232 233 assert(offset < buffer->width0); 234 assert(offset + length <= buffer->width0); 235 assert(length); 236 237 u_box_1d(offset, length, &box); 238 239 *transfer = pipe->get_transfer( pipe, 240 buffer, 241 0, 242 usage, 243 &box); 244 245 if (*transfer == NULL) 246 return NULL; 247 248 map = pipe->transfer_map( pipe, *transfer ); 249 if (map == NULL) { 250 pipe->transfer_destroy( pipe, *transfer ); 251 *transfer = NULL; 252 return NULL; 253 } 254 255 return map; 256} 257 258 259static INLINE void * 260pipe_buffer_map(struct pipe_context *pipe, 261 struct pipe_resource *buffer, 262 unsigned usage, 263 struct pipe_transfer **transfer) 264{ 265 return pipe_buffer_map_range(pipe, buffer, 0, buffer->width0, usage, transfer); 266} 267 268 269static INLINE void 270pipe_buffer_unmap(struct pipe_context *pipe, 271 struct pipe_transfer *transfer) 272{ 273 if (transfer) { 274 pipe->transfer_unmap(pipe, transfer); 275 pipe->transfer_destroy(pipe, transfer); 276 } 277} 278 279static INLINE void 280pipe_buffer_flush_mapped_range(struct pipe_context *pipe, 281 struct pipe_transfer *transfer, 282 unsigned offset, 283 unsigned length) 284{ 285 struct pipe_box box; 286 int transfer_offset; 287 288 assert(length); 289 assert(transfer->box.x <= offset); 290 assert(offset + length <= transfer->box.x + transfer->box.width); 291 292 /* Match old screen->buffer_flush_mapped_range() behaviour, where 293 * offset parameter is relative to the start of the buffer, not the 294 * mapped range. 295 */ 296 transfer_offset = offset - transfer->box.x; 297 298 u_box_1d(transfer_offset, length, &box); 299 300 pipe->transfer_flush_region(pipe, transfer, &box); 301} 302 303static INLINE void 304pipe_buffer_write(struct pipe_context *pipe, 305 struct pipe_resource *buf, 306 unsigned offset, 307 unsigned size, 308 const void *data) 309{ 310 struct pipe_box box; 311 unsigned usage = PIPE_TRANSFER_WRITE; 312 313 if (offset == 0 && size == buf->width0) { 314 usage |= PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE; 315 } else { 316 usage |= PIPE_TRANSFER_DISCARD_RANGE; 317 } 318 319 u_box_1d(offset, size, &box); 320 321 pipe->transfer_inline_write( pipe, 322 buf, 323 0, 324 usage, 325 &box, 326 data, 327 size, 328 0); 329} 330 331/** 332 * Special case for writing non-overlapping ranges. 333 * 334 * We can avoid GPU/CPU synchronization when writing range that has never 335 * been written before. 336 */ 337static INLINE void 338pipe_buffer_write_nooverlap(struct pipe_context *pipe, 339 struct pipe_resource *buf, 340 unsigned offset, unsigned size, 341 const void *data) 342{ 343 struct pipe_box box; 344 345 u_box_1d(offset, size, &box); 346 347 pipe->transfer_inline_write(pipe, 348 buf, 349 0, 350 (PIPE_TRANSFER_WRITE | 351 PIPE_TRANSFER_NOOVERWRITE), 352 &box, 353 data, 354 0, 0); 355} 356 357static INLINE void 358pipe_buffer_read(struct pipe_context *pipe, 359 struct pipe_resource *buf, 360 unsigned offset, 361 unsigned size, 362 void *data) 363{ 364 struct pipe_transfer *src_transfer; 365 ubyte *map; 366 367 map = (ubyte *) pipe_buffer_map_range(pipe, 368 buf, 369 offset, size, 370 PIPE_TRANSFER_READ, 371 &src_transfer); 372 373 if (map) 374 memcpy(data, map, size); 375 376 pipe_buffer_unmap(pipe, src_transfer); 377} 378 379static INLINE struct pipe_transfer * 380pipe_get_transfer( struct pipe_context *context, 381 struct pipe_resource *resource, 382 unsigned level, unsigned layer, 383 enum pipe_transfer_usage usage, 384 unsigned x, unsigned y, 385 unsigned w, unsigned h) 386{ 387 struct pipe_box box; 388 u_box_2d_zslice( x, y, layer, w, h, &box ); 389 return context->get_transfer( context, 390 resource, 391 level, 392 usage, 393 &box ); 394} 395 396static INLINE void * 397pipe_transfer_map( struct pipe_context *context, 398 struct pipe_transfer *transfer ) 399{ 400 return context->transfer_map( context, transfer ); 401} 402 403static INLINE void 404pipe_transfer_unmap( struct pipe_context *context, 405 struct pipe_transfer *transfer ) 406{ 407 context->transfer_unmap( context, transfer ); 408} 409 410 411static INLINE void 412pipe_transfer_destroy( struct pipe_context *context, 413 struct pipe_transfer *transfer ) 414{ 415 context->transfer_destroy(context, transfer); 416} 417 418 419static INLINE boolean util_get_offset( 420 const struct pipe_rasterizer_state *templ, 421 unsigned fill_mode) 422{ 423 switch(fill_mode) { 424 case PIPE_POLYGON_MODE_POINT: 425 return templ->offset_point; 426 case PIPE_POLYGON_MODE_LINE: 427 return templ->offset_line; 428 case PIPE_POLYGON_MODE_FILL: 429 return templ->offset_tri; 430 default: 431 assert(0); 432 return FALSE; 433 } 434} 435 436/** 437 * This function is used to copy an array of pipe_vertex_buffer structures, 438 * while properly referencing the pipe_vertex_buffer::buffer member. 439 * 440 * \sa util_copy_framebuffer_state 441 */ 442static INLINE void util_copy_vertex_buffers(struct pipe_vertex_buffer *dst, 443 unsigned *dst_count, 444 const struct pipe_vertex_buffer *src, 445 unsigned src_count) 446{ 447 unsigned i; 448 449 /* Reference the buffers of 'src' in 'dst'. */ 450 for (i = 0; i < src_count; i++) { 451 pipe_resource_reference(&dst[i].buffer, src[i].buffer); 452 } 453 /* Unreference the rest of the buffers in 'dst'. */ 454 for (; i < *dst_count; i++) { 455 pipe_resource_reference(&dst[i].buffer, NULL); 456 } 457 458 /* Update the size of 'dst' and copy over the other members 459 * of pipe_vertex_buffer. */ 460 *dst_count = src_count; 461 memcpy(dst, src, src_count * sizeof(struct pipe_vertex_buffer)); 462} 463 464#ifdef __cplusplus 465} 466#endif 467 468#endif /* U_INLINES_H */ 469