Merge branch 'gallium-nopointsizeminmax'
[mesa.git] / src / gallium / auxiliary / pipebuffer / pb_bufmgr_debug.c
1 /**************************************************************************
2 *
3 * Copyright 2007-2008 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 /**
29 * \file
30 * Debug buffer manager to detect buffer under- and overflows.
31 *
32 * \author Jose Fonseca <jrfonseca@tungstengraphics.com>
33 */
34
35
36 #include "pipe/p_compiler.h"
37 #include "util/u_debug.h"
38 #include "os/os_thread.h"
39 #include "util/u_math.h"
40 #include "util/u_memory.h"
41 #include "util/u_double_list.h"
42 #include "util/u_time.h"
43 #include "util/u_debug_stack.h"
44
45 #include "pb_buffer.h"
46 #include "pb_bufmgr.h"
47
48
49 #ifdef DEBUG
50
51
52 #define PB_DEBUG_CREATE_BACKTRACE 8
53 #define PB_DEBUG_MAP_BACKTRACE 8
54
55
56 /**
57 * Convenience macro (type safe).
58 */
59 #define SUPER(__derived) (&(__derived)->base)
60
61
62 struct pb_debug_manager;
63
64
65 /**
66 * Wrapper around a pipe buffer which adds delayed destruction.
67 */
68 struct pb_debug_buffer
69 {
70 struct pb_buffer base;
71
72 struct pb_buffer *buffer;
73 struct pb_debug_manager *mgr;
74
75 pb_size underflow_size;
76 pb_size overflow_size;
77
78 struct debug_stack_frame create_backtrace[PB_DEBUG_CREATE_BACKTRACE];
79
80 pipe_mutex mutex;
81 unsigned map_count;
82 struct debug_stack_frame map_backtrace[PB_DEBUG_MAP_BACKTRACE];
83
84 struct list_head head;
85 };
86
87
88 struct pb_debug_manager
89 {
90 struct pb_manager base;
91
92 struct pb_manager *provider;
93
94 pb_size underflow_size;
95 pb_size overflow_size;
96
97 pipe_mutex mutex;
98 struct list_head list;
99 };
100
101
102 static INLINE struct pb_debug_buffer *
103 pb_debug_buffer(struct pb_buffer *buf)
104 {
105 assert(buf);
106 return (struct pb_debug_buffer *)buf;
107 }
108
109
110 static INLINE struct pb_debug_manager *
111 pb_debug_manager(struct pb_manager *mgr)
112 {
113 assert(mgr);
114 return (struct pb_debug_manager *)mgr;
115 }
116
117
118 static const uint8_t random_pattern[32] = {
119 0xaf, 0xcf, 0xa5, 0xa2, 0xc2, 0x63, 0x15, 0x1a,
120 0x7e, 0xe2, 0x7e, 0x84, 0x15, 0x49, 0xa2, 0x1e,
121 0x49, 0x63, 0xf5, 0x52, 0x74, 0x66, 0x9e, 0xc4,
122 0x6d, 0xcf, 0x2c, 0x4a, 0x74, 0xe6, 0xfd, 0x94
123 };
124
125
126 static INLINE void
127 fill_random_pattern(uint8_t *dst, pb_size size)
128 {
129 pb_size i = 0;
130 while(size--) {
131 *dst++ = random_pattern[i++];
132 i &= sizeof(random_pattern) - 1;
133 }
134 }
135
136
137 static INLINE boolean
138 check_random_pattern(const uint8_t *dst, pb_size size,
139 pb_size *min_ofs, pb_size *max_ofs)
140 {
141 boolean result = TRUE;
142 pb_size i;
143 *min_ofs = size;
144 *max_ofs = 0;
145 for(i = 0; i < size; ++i) {
146 if(*dst++ != random_pattern[i % sizeof(random_pattern)]) {
147 *min_ofs = MIN2(*min_ofs, i);
148 *max_ofs = MAX2(*max_ofs, i);
149 result = FALSE;
150 }
151 }
152 return result;
153 }
154
155
156 static void
157 pb_debug_buffer_fill(struct pb_debug_buffer *buf)
158 {
159 uint8_t *map;
160
161 map = pb_map(buf->buffer, PIPE_BUFFER_USAGE_CPU_WRITE);
162 assert(map);
163 if(map) {
164 fill_random_pattern(map, buf->underflow_size);
165 fill_random_pattern(map + buf->underflow_size + buf->base.base.size,
166 buf->overflow_size);
167 pb_unmap(buf->buffer);
168 }
169 }
170
171
172 /**
173 * Check for under/over flows.
174 *
175 * Should be called with the buffer unmaped.
176 */
177 static void
178 pb_debug_buffer_check(struct pb_debug_buffer *buf)
179 {
180 uint8_t *map;
181
182 map = pb_map(buf->buffer, PIPE_BUFFER_USAGE_CPU_READ);
183 assert(map);
184 if(map) {
185 boolean underflow, overflow;
186 pb_size min_ofs, max_ofs;
187
188 underflow = !check_random_pattern(map, buf->underflow_size,
189 &min_ofs, &max_ofs);
190 if(underflow) {
191 debug_printf("buffer underflow (offset -%u%s to -%u bytes) detected\n",
192 buf->underflow_size - min_ofs,
193 min_ofs == 0 ? "+" : "",
194 buf->underflow_size - max_ofs);
195 }
196
197 overflow = !check_random_pattern(map + buf->underflow_size + buf->base.base.size,
198 buf->overflow_size,
199 &min_ofs, &max_ofs);
200 if(overflow) {
201 debug_printf("buffer overflow (size %u plus offset %u to %u%s bytes) detected\n",
202 buf->base.base.size,
203 min_ofs,
204 max_ofs,
205 max_ofs == buf->overflow_size - 1 ? "+" : "");
206 }
207
208 if(underflow || overflow)
209 debug_backtrace_dump(buf->create_backtrace, PB_DEBUG_CREATE_BACKTRACE);
210
211 debug_assert(!underflow && !overflow);
212
213 /* re-fill if not aborted */
214 if(underflow)
215 fill_random_pattern(map, buf->underflow_size);
216 if(overflow)
217 fill_random_pattern(map + buf->underflow_size + buf->base.base.size,
218 buf->overflow_size);
219
220 pb_unmap(buf->buffer);
221 }
222 }
223
224
225 static void
226 pb_debug_buffer_destroy(struct pb_buffer *_buf)
227 {
228 struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
229 struct pb_debug_manager *mgr = buf->mgr;
230
231 assert(!pipe_is_referenced(&buf->base.base.reference));
232
233 pb_debug_buffer_check(buf);
234
235 pipe_mutex_lock(mgr->mutex);
236 LIST_DEL(&buf->head);
237 pipe_mutex_unlock(mgr->mutex);
238
239 pipe_mutex_destroy(buf->mutex);
240
241 pb_reference(&buf->buffer, NULL);
242 FREE(buf);
243 }
244
245
246 static void *
247 pb_debug_buffer_map(struct pb_buffer *_buf,
248 unsigned flags)
249 {
250 struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
251 void *map;
252
253 pb_debug_buffer_check(buf);
254
255 map = pb_map(buf->buffer, flags);
256 if(!map)
257 return NULL;
258
259 if(map) {
260 pipe_mutex_lock(buf->mutex);
261 ++buf->map_count;
262 debug_backtrace_capture(buf->map_backtrace, 1, PB_DEBUG_MAP_BACKTRACE);
263 pipe_mutex_unlock(buf->mutex);
264 }
265
266 return (uint8_t *)map + buf->underflow_size;
267 }
268
269
270 static void
271 pb_debug_buffer_unmap(struct pb_buffer *_buf)
272 {
273 struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
274
275 pipe_mutex_lock(buf->mutex);
276 assert(buf->map_count);
277 if(buf->map_count)
278 --buf->map_count;
279 pipe_mutex_unlock(buf->mutex);
280
281 pb_unmap(buf->buffer);
282
283 pb_debug_buffer_check(buf);
284 }
285
286
287 static void
288 pb_debug_buffer_get_base_buffer(struct pb_buffer *_buf,
289 struct pb_buffer **base_buf,
290 pb_size *offset)
291 {
292 struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
293 pb_get_base_buffer(buf->buffer, base_buf, offset);
294 *offset += buf->underflow_size;
295 }
296
297
298 static enum pipe_error
299 pb_debug_buffer_validate(struct pb_buffer *_buf,
300 struct pb_validate *vl,
301 unsigned flags)
302 {
303 struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
304
305 pipe_mutex_lock(buf->mutex);
306 if(buf->map_count) {
307 debug_printf("%s: attempting to validate a mapped buffer\n", __FUNCTION__);
308 debug_printf("last map backtrace is\n");
309 debug_backtrace_dump(buf->map_backtrace, PB_DEBUG_MAP_BACKTRACE);
310 }
311 pipe_mutex_unlock(buf->mutex);
312
313 pb_debug_buffer_check(buf);
314
315 return pb_validate(buf->buffer, vl, flags);
316 }
317
318
319 static void
320 pb_debug_buffer_fence(struct pb_buffer *_buf,
321 struct pipe_fence_handle *fence)
322 {
323 struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
324 pb_fence(buf->buffer, fence);
325 }
326
327
328 const struct pb_vtbl
329 pb_debug_buffer_vtbl = {
330 pb_debug_buffer_destroy,
331 pb_debug_buffer_map,
332 pb_debug_buffer_unmap,
333 pb_debug_buffer_validate,
334 pb_debug_buffer_fence,
335 pb_debug_buffer_get_base_buffer
336 };
337
338
339 static void
340 pb_debug_manager_dump(struct pb_debug_manager *mgr)
341 {
342 struct list_head *curr, *next;
343 struct pb_debug_buffer *buf;
344
345 pipe_mutex_lock(mgr->mutex);
346
347 curr = mgr->list.next;
348 next = curr->next;
349 while(curr != &mgr->list) {
350 buf = LIST_ENTRY(struct pb_debug_buffer, curr, head);
351
352 debug_printf("buffer = %p\n", buf);
353 debug_printf(" .size = 0x%x\n", buf->base.base.size);
354 debug_backtrace_dump(buf->create_backtrace, PB_DEBUG_CREATE_BACKTRACE);
355
356 curr = next;
357 next = curr->next;
358 }
359
360 pipe_mutex_unlock(mgr->mutex);
361 }
362
363
364 static struct pb_buffer *
365 pb_debug_manager_create_buffer(struct pb_manager *_mgr,
366 pb_size size,
367 const struct pb_desc *desc)
368 {
369 struct pb_debug_manager *mgr = pb_debug_manager(_mgr);
370 struct pb_debug_buffer *buf;
371 struct pb_desc real_desc;
372 pb_size real_size;
373
374 assert(size);
375 assert(desc->alignment);
376
377 buf = CALLOC_STRUCT(pb_debug_buffer);
378 if(!buf)
379 return NULL;
380
381 real_size = mgr->underflow_size + size + mgr->overflow_size;
382 real_desc = *desc;
383 real_desc.usage |= PIPE_BUFFER_USAGE_CPU_WRITE;
384 real_desc.usage |= PIPE_BUFFER_USAGE_CPU_READ;
385
386 buf->buffer = mgr->provider->create_buffer(mgr->provider,
387 real_size,
388 &real_desc);
389 if(!buf->buffer) {
390 FREE(buf);
391 #if 0
392 pipe_mutex_lock(mgr->mutex);
393 debug_printf("%s: failed to create buffer\n", __FUNCTION__);
394 if(!LIST_IS_EMPTY(&mgr->list))
395 pb_debug_manager_dump(mgr);
396 pipe_mutex_unlock(mgr->mutex);
397 #endif
398 return NULL;
399 }
400
401 assert(pipe_is_referenced(&buf->buffer->base.reference));
402 assert(pb_check_alignment(real_desc.alignment, buf->buffer->base.alignment));
403 assert(pb_check_usage(real_desc.usage, buf->buffer->base.usage));
404 assert(buf->buffer->base.size >= real_size);
405
406 pipe_reference_init(&buf->base.base.reference, 1);
407 buf->base.base.alignment = desc->alignment;
408 buf->base.base.usage = desc->usage;
409 buf->base.base.size = size;
410
411 buf->base.vtbl = &pb_debug_buffer_vtbl;
412 buf->mgr = mgr;
413
414 buf->underflow_size = mgr->underflow_size;
415 buf->overflow_size = buf->buffer->base.size - buf->underflow_size - size;
416
417 debug_backtrace_capture(buf->create_backtrace, 1, PB_DEBUG_CREATE_BACKTRACE);
418
419 pb_debug_buffer_fill(buf);
420
421 pipe_mutex_init(buf->mutex);
422
423 pipe_mutex_lock(mgr->mutex);
424 LIST_ADDTAIL(&buf->head, &mgr->list);
425 pipe_mutex_unlock(mgr->mutex);
426
427 return &buf->base;
428 }
429
430
431 static void
432 pb_debug_manager_flush(struct pb_manager *_mgr)
433 {
434 struct pb_debug_manager *mgr = pb_debug_manager(_mgr);
435 assert(mgr->provider->flush);
436 if(mgr->provider->flush)
437 mgr->provider->flush(mgr->provider);
438 }
439
440
441 static void
442 pb_debug_manager_destroy(struct pb_manager *_mgr)
443 {
444 struct pb_debug_manager *mgr = pb_debug_manager(_mgr);
445
446 pipe_mutex_lock(mgr->mutex);
447 if(!LIST_IS_EMPTY(&mgr->list)) {
448 debug_printf("%s: unfreed buffers\n", __FUNCTION__);
449 pb_debug_manager_dump(mgr);
450 }
451 pipe_mutex_unlock(mgr->mutex);
452
453 pipe_mutex_destroy(mgr->mutex);
454 mgr->provider->destroy(mgr->provider);
455 FREE(mgr);
456 }
457
458
459 struct pb_manager *
460 pb_debug_manager_create(struct pb_manager *provider,
461 pb_size underflow_size, pb_size overflow_size)
462 {
463 struct pb_debug_manager *mgr;
464
465 if(!provider)
466 return NULL;
467
468 mgr = CALLOC_STRUCT(pb_debug_manager);
469 if (!mgr)
470 return NULL;
471
472 mgr->base.destroy = pb_debug_manager_destroy;
473 mgr->base.create_buffer = pb_debug_manager_create_buffer;
474 mgr->base.flush = pb_debug_manager_flush;
475 mgr->provider = provider;
476 mgr->underflow_size = underflow_size;
477 mgr->overflow_size = overflow_size;
478
479 pipe_mutex_init(mgr->mutex);
480 LIST_INITHEAD(&mgr->list);
481
482 return &mgr->base;
483 }
484
485
486 #else /* !DEBUG */
487
488
489 struct pb_manager *
490 pb_debug_manager_create(struct pb_manager *provider,
491 pb_size underflow_size, pb_size overflow_size)
492 {
493 return provider;
494 }
495
496
497 #endif /* !DEBUG */