1 /**************************************************************************
3 * Copyright 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas.
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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.
26 **************************************************************************/
30 * Debug buffer manager to detect buffer under- and overflows.
32 * \author Jose Fonseca <jrfonseca@tungstengraphics.com>
36 #include "pipe/p_compiler.h"
37 #include "pipe/p_debug.h"
38 #include "pipe/p_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"
44 #include "pb_buffer.h"
45 #include "pb_bufmgr.h"
52 * Convenience macro (type safe).
54 #define SUPER(__derived) (&(__derived)->base)
57 struct pb_debug_manager
;
61 * Wrapper around a pipe buffer which adds delayed destruction.
63 struct pb_debug_buffer
65 struct pb_buffer base
;
67 struct pb_buffer
*buffer
;
68 struct pb_debug_manager
*mgr
;
70 size_t underflow_size
;
75 struct pb_debug_manager
77 struct pb_manager base
;
79 struct pb_manager
*provider
;
85 static INLINE
struct pb_debug_buffer
*
86 pb_debug_buffer(struct pb_buffer
*buf
)
89 return (struct pb_debug_buffer
*)buf
;
93 static INLINE
struct pb_debug_manager
*
94 pb_debug_manager(struct pb_manager
*mgr
)
97 return (struct pb_debug_manager
*)mgr
;
101 static const uint8_t random_pattern
[32] = {
102 0xaf, 0xcf, 0xa5, 0xa2, 0xc2, 0x63, 0x15, 0x1a,
103 0x7e, 0xe2, 0x7e, 0x84, 0x15, 0x49, 0xa2, 0x1e,
104 0x49, 0x63, 0xf5, 0x52, 0x74, 0x66, 0x9e, 0xc4,
105 0x6d, 0xcf, 0x2c, 0x4a, 0x74, 0xe6, 0xfd, 0x94
110 fill_random_pattern(uint8_t *dst
, size_t size
)
114 *dst
++ = random_pattern
[i
++];
115 i
&= sizeof(random_pattern
) - 1;
120 static INLINE boolean
121 check_random_pattern(const uint8_t *dst
, size_t size
,
122 size_t *min_ofs
, size_t *max_ofs
)
124 boolean result
= TRUE
;
128 for(i
= 0; i
< size
; ++i
) {
129 if(*dst
++ != random_pattern
[i
% sizeof(random_pattern
)]) {
130 *min_ofs
= MIN2(*min_ofs
, i
);
131 *max_ofs
= MAX2(*max_ofs
, i
);
140 pb_debug_buffer_fill(struct pb_debug_buffer
*buf
)
144 map
= pb_map(buf
->buffer
, PIPE_BUFFER_USAGE_CPU_WRITE
);
147 fill_random_pattern(map
, buf
->underflow_size
);
148 fill_random_pattern(map
+ buf
->underflow_size
+ buf
->base
.base
.size
,
150 pb_unmap(buf
->buffer
);
156 * Check for under/over flows.
158 * Should be called with the buffer unmaped.
161 pb_debug_buffer_check(struct pb_debug_buffer
*buf
)
165 map
= pb_map(buf
->buffer
, PIPE_BUFFER_USAGE_CPU_READ
);
168 boolean underflow
, overflow
;
169 size_t min_ofs
, max_ofs
;
171 underflow
= !check_random_pattern(map
, buf
->underflow_size
,
174 debug_printf("buffer underflow (offset -%u%s to -%u bytes) detected\n",
175 buf
->underflow_size
- min_ofs
,
176 min_ofs
== 0 ? "+" : "",
177 buf
->underflow_size
- max_ofs
);
180 overflow
= !check_random_pattern(map
+ buf
->underflow_size
+ buf
->base
.base
.size
,
184 debug_printf("buffer overflow (size %u plus offset %u to %u%s bytes) detected\n",
188 max_ofs
== buf
->overflow_size
- 1 ? "+" : "");
191 debug_assert(!underflow
&& !overflow
);
193 /* re-fill if not aborted */
195 fill_random_pattern(map
, buf
->underflow_size
);
197 fill_random_pattern(map
+ buf
->underflow_size
+ buf
->base
.base
.size
,
200 pb_unmap(buf
->buffer
);
206 pb_debug_buffer_destroy(struct pb_buffer
*_buf
)
208 struct pb_debug_buffer
*buf
= pb_debug_buffer(_buf
);
210 assert(!buf
->base
.base
.refcount
);
212 pb_debug_buffer_check(buf
);
214 pb_reference(&buf
->buffer
, NULL
);
220 pb_debug_buffer_map(struct pb_buffer
*_buf
,
223 struct pb_debug_buffer
*buf
= pb_debug_buffer(_buf
);
226 pb_debug_buffer_check(buf
);
228 map
= pb_map(buf
->buffer
, flags
);
232 return (uint8_t *)map
+ buf
->underflow_size
;
237 pb_debug_buffer_unmap(struct pb_buffer
*_buf
)
239 struct pb_debug_buffer
*buf
= pb_debug_buffer(_buf
);
240 pb_unmap(buf
->buffer
);
242 pb_debug_buffer_check(buf
);
247 pb_debug_buffer_get_base_buffer(struct pb_buffer
*_buf
,
248 struct pb_buffer
**base_buf
,
251 struct pb_debug_buffer
*buf
= pb_debug_buffer(_buf
);
252 pb_get_base_buffer(buf
->buffer
, base_buf
, offset
);
253 *offset
+= buf
->underflow_size
;
257 static enum pipe_error
258 pb_debug_buffer_validate(struct pb_buffer
*_buf
,
259 struct pb_validate
*vl
,
262 struct pb_debug_buffer
*buf
= pb_debug_buffer(_buf
);
264 pb_debug_buffer_check(buf
);
266 return pb_validate(buf
->buffer
, vl
, flags
);
271 pb_debug_buffer_fence(struct pb_buffer
*_buf
,
272 struct pipe_fence_handle
*fence
)
274 struct pb_debug_buffer
*buf
= pb_debug_buffer(_buf
);
275 pb_fence(buf
->buffer
, fence
);
280 pb_debug_buffer_vtbl
= {
281 pb_debug_buffer_destroy
,
283 pb_debug_buffer_unmap
,
284 pb_debug_buffer_validate
,
285 pb_debug_buffer_fence
,
286 pb_debug_buffer_get_base_buffer
290 static struct pb_buffer
*
291 pb_debug_manager_create_buffer(struct pb_manager
*_mgr
,
293 const struct pb_desc
*desc
)
295 struct pb_debug_manager
*mgr
= pb_debug_manager(_mgr
);
296 struct pb_debug_buffer
*buf
;
297 struct pb_desc real_desc
;
300 buf
= CALLOC_STRUCT(pb_debug_buffer
);
304 real_size
= size
+ 2*mgr
->band_size
;
306 real_desc
.usage
|= PIPE_BUFFER_USAGE_CPU_WRITE
;
307 real_desc
.usage
|= PIPE_BUFFER_USAGE_CPU_READ
;
309 buf
->buffer
= mgr
->provider
->create_buffer(mgr
->provider
,
317 assert(buf
->buffer
->base
.refcount
>= 1);
318 assert(pb_check_alignment(real_desc
.alignment
, buf
->buffer
->base
.alignment
));
319 assert(pb_check_usage(real_desc
.usage
, buf
->buffer
->base
.usage
));
320 assert(buf
->buffer
->base
.size
>= real_size
);
322 buf
->base
.base
.refcount
= 1;
323 buf
->base
.base
.alignment
= desc
->alignment
;
324 buf
->base
.base
.usage
= desc
->usage
;
325 buf
->base
.base
.size
= size
;
327 buf
->base
.vtbl
= &pb_debug_buffer_vtbl
;
330 buf
->underflow_size
= mgr
->band_size
;
331 buf
->overflow_size
= buf
->buffer
->base
.size
- buf
->underflow_size
- size
;
333 pb_debug_buffer_fill(buf
);
340 pb_debug_manager_flush(struct pb_manager
*_mgr
)
342 struct pb_debug_manager
*mgr
= pb_debug_manager(_mgr
);
343 assert(mgr
->provider
->flush
);
344 if(mgr
->provider
->flush
)
345 mgr
->provider
->flush(mgr
->provider
);
350 pb_debug_manager_destroy(struct pb_manager
*_mgr
)
352 struct pb_debug_manager
*mgr
= pb_debug_manager(_mgr
);
353 mgr
->provider
->destroy(mgr
->provider
);
359 pb_debug_manager_create(struct pb_manager
*provider
, size_t band_size
)
361 struct pb_debug_manager
*mgr
;
366 mgr
= CALLOC_STRUCT(pb_debug_manager
);
370 mgr
->base
.destroy
= pb_debug_manager_destroy
;
371 mgr
->base
.create_buffer
= pb_debug_manager_create_buffer
;
372 mgr
->base
.flush
= pb_debug_manager_flush
;
373 mgr
->provider
= provider
;
374 mgr
->band_size
= band_size
;
384 pb_debug_manager_create(struct pb_manager
*provider
, size_t band_size
)