u_inlines.h revision 4c7001462607e6e99e474d6271dd481d3f8f201c
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_surface_reset(struct pipe_surface* ps, struct pipe_resource *pt, 140 unsigned level, unsigned layer, unsigned flags) 141{ 142 pipe_resource_reference(&ps->texture, pt); 143 ps->format = pt->format; 144 ps->width = u_minify(pt->width0, level); 145 ps->height = u_minify(pt->height0, level); 146 ps->usage = flags; 147 ps->u.tex.level = level; 148 ps->u.tex.first_layer = ps->u.tex.last_layer = layer; 149} 150 151static INLINE void 152pipe_surface_init(struct pipe_surface* ps, struct pipe_resource *pt, 153 unsigned level, unsigned layer, unsigned flags) 154{ 155 ps->texture = 0; 156 pipe_reference_init(&ps->reference, 1); 157 pipe_surface_reset(ps, pt, level, layer, flags); 158} 159 160/* 161 * Convenience wrappers for screen buffer functions. 162 */ 163 164static INLINE struct pipe_resource * 165pipe_buffer_create( struct pipe_screen *screen, 166 unsigned bind, 167 unsigned size ) 168{ 169 struct pipe_resource buffer; 170 memset(&buffer, 0, sizeof buffer); 171 buffer.target = PIPE_BUFFER; 172 buffer.format = PIPE_FORMAT_R8_UNORM; /* want TYPELESS or similar */ 173 buffer.bind = bind; 174 buffer.usage = PIPE_USAGE_DEFAULT; 175 buffer.flags = 0; 176 buffer.width0 = size; 177 buffer.height0 = 1; 178 buffer.depth0 = 1; 179 buffer.array_size = 1; 180 return screen->resource_create(screen, &buffer); 181} 182 183 184static INLINE struct pipe_resource * 185pipe_user_buffer_create( struct pipe_screen *screen, void *ptr, unsigned size, 186 unsigned usage ) 187{ 188 return screen->user_buffer_create(screen, ptr, size, usage); 189} 190 191static INLINE void * 192pipe_buffer_map_range(struct pipe_context *pipe, 193 struct pipe_resource *buffer, 194 unsigned offset, 195 unsigned length, 196 unsigned usage, 197 struct pipe_transfer **transfer) 198{ 199 struct pipe_box box; 200 void *map; 201 202 assert(offset < buffer->width0); 203 assert(offset + length <= buffer->width0); 204 assert(length); 205 206 u_box_1d(offset, length, &box); 207 208 *transfer = pipe->get_transfer( pipe, 209 buffer, 210 0, 211 usage, 212 &box); 213 214 if (*transfer == NULL) 215 return NULL; 216 217 map = pipe->transfer_map( pipe, *transfer ); 218 if (map == NULL) { 219 pipe->transfer_destroy( pipe, *transfer ); 220 return NULL; 221 } 222 223 /* Match old screen->buffer_map_range() behaviour, return pointer 224 * to where the beginning of the buffer would be: 225 */ 226 return (void *)((char *)map - offset); 227} 228 229 230static INLINE void * 231pipe_buffer_map(struct pipe_context *pipe, 232 struct pipe_resource *buffer, 233 unsigned usage, 234 struct pipe_transfer **transfer) 235{ 236 return pipe_buffer_map_range(pipe, buffer, 0, buffer->width0, usage, transfer); 237} 238 239 240static INLINE void 241pipe_buffer_unmap(struct pipe_context *pipe, 242 struct pipe_resource *buf, 243 struct pipe_transfer *transfer) 244{ 245 if (transfer) { 246 pipe->transfer_unmap(pipe, transfer); 247 pipe->transfer_destroy(pipe, transfer); 248 } 249} 250 251static INLINE void 252pipe_buffer_flush_mapped_range(struct pipe_context *pipe, 253 struct pipe_transfer *transfer, 254 unsigned offset, 255 unsigned length) 256{ 257 struct pipe_box box; 258 int transfer_offset; 259 260 assert(length); 261 assert(transfer->box.x <= offset); 262 assert(offset + length <= transfer->box.x + transfer->box.width); 263 264 /* Match old screen->buffer_flush_mapped_range() behaviour, where 265 * offset parameter is relative to the start of the buffer, not the 266 * mapped range. 267 */ 268 transfer_offset = offset - transfer->box.x; 269 270 u_box_1d(transfer_offset, length, &box); 271 272 pipe->transfer_flush_region(pipe, transfer, &box); 273} 274 275static INLINE void 276pipe_buffer_write(struct pipe_context *pipe, 277 struct pipe_resource *buf, 278 unsigned offset, 279 unsigned size, 280 const void *data) 281{ 282 struct pipe_box box; 283 284 u_box_1d(offset, size, &box); 285 286 pipe->transfer_inline_write( pipe, 287 buf, 288 0, 289 PIPE_TRANSFER_WRITE, 290 &box, 291 data, 292 size, 293 0); 294} 295 296/** 297 * Special case for writing non-overlapping ranges. 298 * 299 * We can avoid GPU/CPU synchronization when writing range that has never 300 * been written before. 301 */ 302static INLINE void 303pipe_buffer_write_nooverlap(struct pipe_context *pipe, 304 struct pipe_resource *buf, 305 unsigned offset, unsigned size, 306 const void *data) 307{ 308 struct pipe_box box; 309 310 u_box_1d(offset, size, &box); 311 312 pipe->transfer_inline_write(pipe, 313 buf, 314 0, 315 (PIPE_TRANSFER_WRITE | 316 PIPE_TRANSFER_NOOVERWRITE), 317 &box, 318 data, 319 0, 0); 320} 321 322static INLINE void 323pipe_buffer_read(struct pipe_context *pipe, 324 struct pipe_resource *buf, 325 unsigned offset, 326 unsigned size, 327 void *data) 328{ 329 struct pipe_transfer *src_transfer; 330 ubyte *map; 331 332 map = (ubyte *) pipe_buffer_map_range(pipe, 333 buf, 334 offset, size, 335 PIPE_TRANSFER_READ, 336 &src_transfer); 337 338 if (map) 339 memcpy(data, map + offset, size); 340 341 pipe_buffer_unmap(pipe, buf, src_transfer); 342} 343 344static INLINE struct pipe_transfer * 345pipe_get_transfer( struct pipe_context *context, 346 struct pipe_resource *resource, 347 unsigned level, unsigned layer, 348 enum pipe_transfer_usage usage, 349 unsigned x, unsigned y, 350 unsigned w, unsigned h) 351{ 352 struct pipe_box box; 353 u_box_2d_zslice( x, y, layer, w, h, &box ); 354 return context->get_transfer( context, 355 resource, 356 level, 357 usage, 358 &box ); 359} 360 361static INLINE void * 362pipe_transfer_map( struct pipe_context *context, 363 struct pipe_transfer *transfer ) 364{ 365 return context->transfer_map( context, transfer ); 366} 367 368static INLINE void 369pipe_transfer_unmap( struct pipe_context *context, 370 struct pipe_transfer *transfer ) 371{ 372 context->transfer_unmap( context, transfer ); 373} 374 375 376static INLINE void 377pipe_transfer_destroy( struct pipe_context *context, 378 struct pipe_transfer *transfer ) 379{ 380 context->transfer_destroy(context, transfer); 381} 382 383 384static INLINE boolean util_get_offset( 385 const struct pipe_rasterizer_state *templ, 386 unsigned fill_mode) 387{ 388 switch(fill_mode) { 389 case PIPE_POLYGON_MODE_POINT: 390 return templ->offset_point; 391 case PIPE_POLYGON_MODE_LINE: 392 return templ->offset_line; 393 case PIPE_POLYGON_MODE_FILL: 394 return templ->offset_tri; 395 default: 396 assert(0); 397 return FALSE; 398 } 399} 400 401#ifdef __cplusplus 402} 403#endif 404 405#endif /* U_INLINES_H */ 406