util: Make the reference debuggin code more C++ friendly.
[mesa.git] / src / gallium / auxiliary / util / u_inlines.h
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
44 extern "C" {
45 #endif
46
47
48 /*
49 * Reference counting helper functions.
50 */
51
52
53 static INLINE void
54 pipe_reference_init(struct pipe_reference *reference, unsigned count)
55 {
56 p_atomic_set(&reference->count, count);
57 }
58
59 static INLINE boolean
60 pipe_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 */
71 static INLINE boolean
72 pipe_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
98 static INLINE boolean
99 pipe_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
105 static INLINE void
106 pipe_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->texture->screen->tex_surface_destroy(old_surf);
113 *ptr = surf;
114 }
115
116 static INLINE void
117 pipe_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
127 static INLINE void
128 pipe_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
138 static INLINE void
139 pipe_surface_reset(struct pipe_surface* ps, struct pipe_resource *pt,
140 unsigned face, unsigned level, unsigned zslice, 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->face = face;
148 ps->level = level;
149 ps->zslice = zslice;
150 }
151
152 static INLINE void
153 pipe_surface_init(struct pipe_surface* ps, struct pipe_resource *pt,
154 unsigned face, unsigned level, unsigned zslice, unsigned flags)
155 {
156 ps->texture = 0;
157 pipe_reference_init(&ps->reference, 1);
158 pipe_surface_reset(ps, pt, face, level, zslice, flags);
159 }
160
161 /*
162 * Convenience wrappers for screen buffer functions.
163 */
164
165 static INLINE struct pipe_resource *
166 pipe_buffer_create( struct pipe_screen *screen,
167 unsigned bind,
168 unsigned size )
169 {
170 struct pipe_resource buffer;
171 memset(&buffer, 0, sizeof buffer);
172 buffer.target = PIPE_BUFFER;
173 buffer.format = PIPE_FORMAT_R8_UNORM; /* want TYPELESS or similar */
174 buffer.bind = bind;
175 buffer.usage = PIPE_USAGE_DEFAULT;
176 buffer.flags = 0;
177 buffer.width0 = size;
178 buffer.height0 = 1;
179 buffer.depth0 = 1;
180 return screen->resource_create(screen, &buffer);
181 }
182
183
184 static INLINE struct pipe_resource *
185 pipe_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
191 static INLINE void *
192 pipe_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 u_subresource(0, 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
230 static INLINE void *
231 pipe_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
240 static INLINE void
241 pipe_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
251 static INLINE void
252 pipe_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
275 static INLINE void
276 pipe_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 u_subresource(0,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 */
302 static INLINE void
303 pipe_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 u_subresource(0,0),
315 (PIPE_TRANSFER_WRITE |
316 PIPE_TRANSFER_NOOVERWRITE),
317 &box,
318 data,
319 0, 0);
320 }
321
322 static INLINE void
323 pipe_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
344 static INLINE struct pipe_transfer *
345 pipe_get_transfer( struct pipe_context *context,
346 struct pipe_resource *resource,
347 unsigned face, unsigned level,
348 unsigned zslice,
349 enum pipe_transfer_usage usage,
350 unsigned x, unsigned y,
351 unsigned w, unsigned h)
352 {
353 struct pipe_box box;
354 u_box_2d_zslice( x, y, zslice, w, h, &box );
355 return context->get_transfer( context,
356 resource,
357 u_subresource(face, level),
358 usage,
359 &box );
360 }
361
362 static INLINE void *
363 pipe_transfer_map( struct pipe_context *context,
364 struct pipe_transfer *transfer )
365 {
366 return context->transfer_map( context, transfer );
367 }
368
369 static INLINE void
370 pipe_transfer_unmap( struct pipe_context *context,
371 struct pipe_transfer *transfer )
372 {
373 context->transfer_unmap( context, transfer );
374 }
375
376
377 static INLINE void
378 pipe_transfer_destroy( struct pipe_context *context,
379 struct pipe_transfer *transfer )
380 {
381 context->transfer_destroy(context, transfer);
382 }
383
384
385 static INLINE boolean util_get_offset(
386 const struct pipe_rasterizer_state *templ,
387 unsigned fill_mode)
388 {
389 switch(fill_mode) {
390 case PIPE_POLYGON_MODE_POINT:
391 return templ->offset_point;
392 case PIPE_POLYGON_MODE_LINE:
393 return templ->offset_line;
394 case PIPE_POLYGON_MODE_FILL:
395 return templ->offset_tri;
396 default:
397 assert(0);
398 return FALSE;
399 }
400 }
401
402
403 #ifdef __cplusplus
404 }
405 #endif
406
407 #endif /* U_INLINES_H */