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_winsys.h"
39 #include "pipe/p_thread.h"
40 #include "util/u_math.h"
41 #include "util/u_memory.h"
42 #include "util/u_double_list.h"
43 #include "util/u_time.h"
45 #include "pb_buffer.h"
46 #include "pb_bufmgr.h"
53 * Convenience macro (type safe).
55 #define SUPER(__derived) (&(__derived)->base)
58 struct pb_debug_manager
;
62 * Wrapper around a pipe buffer which adds delayed destruction.
64 struct pb_debug_buffer
66 struct pb_buffer base
;
68 struct pb_buffer
*buffer
;
69 struct pb_debug_manager
*mgr
;
71 size_t underflow_size
;
76 struct pb_debug_manager
78 struct pb_manager base
;
80 struct pb_manager
*provider
;
86 static INLINE
struct pb_debug_buffer
*
87 pb_debug_buffer(struct pb_buffer
*buf
)
90 return (struct pb_debug_buffer
*)buf
;
94 static INLINE
struct pb_debug_manager
*
95 pb_debug_manager(struct pb_manager
*mgr
)
98 return (struct pb_debug_manager
*)mgr
;
102 static const uint8_t random_pattern
[32] = {
103 0xaf, 0xcf, 0xa5, 0xa2, 0xc2, 0x63, 0x15, 0x1a,
104 0x7e, 0xe2, 0x7e, 0x84, 0x15, 0x49, 0xa2, 0x1e,
105 0x49, 0x63, 0xf5, 0x52, 0x74, 0x66, 0x9e, 0xc4,
106 0x6d, 0xcf, 0x2c, 0x4a, 0x74, 0xe6, 0xfd, 0x94
111 fill_random_pattern(uint8_t *dst
, size_t size
)
115 *dst
++ = random_pattern
[i
++];
116 i
&= sizeof(random_pattern
) - 1;
121 static INLINE boolean
122 check_random_pattern(const uint8_t *dst
, size_t size
,
123 size_t *min_ofs
, size_t *max_ofs
)
125 boolean result
= TRUE
;
129 for(i
= 0; i
< size
; ++i
) {
130 if(*dst
++ != random_pattern
[i
% sizeof(random_pattern
)]) {
131 *min_ofs
= MIN2(*min_ofs
, i
);
132 *max_ofs
= MAX2(*max_ofs
, i
);
141 pb_debug_buffer_fill(struct pb_debug_buffer
*buf
)
145 map
= pb_map(buf
->buffer
, PIPE_BUFFER_USAGE_CPU_WRITE
);
148 fill_random_pattern(map
, buf
->underflow_size
);
149 fill_random_pattern(map
+ buf
->underflow_size
+ buf
->base
.base
.size
,
151 pb_unmap(buf
->buffer
);
157 * Check for under/over flows.
159 * Should be called with the buffer unmaped.
162 pb_debug_buffer_check(struct pb_debug_buffer
*buf
)
166 map
= pb_map(buf
->buffer
, PIPE_BUFFER_USAGE_CPU_READ
);
169 boolean underflow
, overflow
;
170 size_t min_ofs
, max_ofs
;
172 underflow
= !check_random_pattern(map
, buf
->underflow_size
,
175 debug_printf("buffer underflow (offset -%u%s to -%u bytes) detected\n",
176 buf
->underflow_size
- min_ofs
,
177 min_ofs
== 0 ? "+" : "",
178 buf
->underflow_size
- max_ofs
);
181 overflow
= !check_random_pattern(map
+ buf
->underflow_size
+ buf
->base
.base
.size
,
185 debug_printf("buffer overflow (size %u plus offset %u to %u%s bytes) detected\n",
189 max_ofs
== buf
->overflow_size
- 1 ? "+" : "");
192 debug_assert(!underflow
&& !overflow
);
194 /* re-fill if not aborted */
196 fill_random_pattern(map
, buf
->underflow_size
);
198 fill_random_pattern(map
+ buf
->underflow_size
+ buf
->base
.base
.size
,
201 pb_unmap(buf
->buffer
);
207 pb_debug_buffer_destroy(struct pb_buffer
*_buf
)
209 struct pb_debug_buffer
*buf
= pb_debug_buffer(_buf
);
211 assert(!buf
->base
.base
.refcount
);
213 pb_debug_buffer_check(buf
);
215 pb_reference(&buf
->buffer
, NULL
);
221 pb_debug_buffer_map(struct pb_buffer
*_buf
,
224 struct pb_debug_buffer
*buf
= pb_debug_buffer(_buf
);
227 pb_debug_buffer_check(buf
);
229 map
= pb_map(buf
->buffer
, flags
);
233 return (uint8_t *)map
+ buf
->underflow_size
;
238 pb_debug_buffer_unmap(struct pb_buffer
*_buf
)
240 struct pb_debug_buffer
*buf
= pb_debug_buffer(_buf
);
241 pb_unmap(buf
->buffer
);
243 pb_debug_buffer_check(buf
);
248 pb_debug_buffer_get_base_buffer(struct pb_buffer
*_buf
,
249 struct pb_buffer
**base_buf
,
252 struct pb_debug_buffer
*buf
= pb_debug_buffer(_buf
);
253 pb_get_base_buffer(buf
->buffer
, base_buf
, offset
);
254 *offset
+= buf
->underflow_size
;
258 static enum pipe_error
259 pb_debug_buffer_validate(struct pb_buffer
*_buf
,
260 struct pb_validate
*vl
,
263 struct pb_debug_buffer
*buf
= pb_debug_buffer(_buf
);
265 pb_debug_buffer_check(buf
);
267 return pb_validate(buf
->buffer
, vl
, flags
);
272 pb_debug_buffer_fence(struct pb_buffer
*_buf
,
273 struct pipe_fence_handle
*fence
)
275 struct pb_debug_buffer
*buf
= pb_debug_buffer(_buf
);
276 pb_fence(buf
->buffer
, fence
);
281 pb_debug_buffer_vtbl
= {
282 pb_debug_buffer_destroy
,
284 pb_debug_buffer_unmap
,
285 pb_debug_buffer_validate
,
286 pb_debug_buffer_fence
,
287 pb_debug_buffer_get_base_buffer
291 static struct pb_buffer
*
292 pb_debug_manager_create_buffer(struct pb_manager
*_mgr
,
294 const struct pb_desc
*desc
)
296 struct pb_debug_manager
*mgr
= pb_debug_manager(_mgr
);
297 struct pb_debug_buffer
*buf
;
298 struct pb_desc real_desc
;
301 buf
= CALLOC_STRUCT(pb_debug_buffer
);
305 real_size
= size
+ 2*mgr
->band_size
;
307 real_desc
.usage
|= PIPE_BUFFER_USAGE_CPU_WRITE
;
308 real_desc
.usage
|= PIPE_BUFFER_USAGE_CPU_READ
;
310 buf
->buffer
= mgr
->provider
->create_buffer(mgr
->provider
,
318 assert(buf
->buffer
->base
.refcount
>= 1);
319 assert(pb_check_alignment(real_desc
.alignment
, buf
->buffer
->base
.alignment
));
320 assert(pb_check_usage(real_desc
.usage
, buf
->buffer
->base
.usage
));
321 assert(buf
->buffer
->base
.size
>= real_size
);
323 buf
->base
.base
.refcount
= 1;
324 buf
->base
.base
.alignment
= desc
->alignment
;
325 buf
->base
.base
.usage
= desc
->usage
;
326 buf
->base
.base
.size
= size
;
328 buf
->base
.vtbl
= &pb_debug_buffer_vtbl
;
331 buf
->underflow_size
= mgr
->band_size
;
332 buf
->overflow_size
= buf
->buffer
->base
.size
- buf
->underflow_size
- size
;
334 pb_debug_buffer_fill(buf
);
341 pb_debug_manager_flush(struct pb_manager
*_mgr
)
343 struct pb_debug_manager
*mgr
= pb_debug_manager(_mgr
);
344 assert(mgr
->provider
->flush
);
345 if(mgr
->provider
->flush
)
346 mgr
->provider
->flush(mgr
->provider
);
351 pb_debug_manager_destroy(struct pb_manager
*_mgr
)
353 struct pb_debug_manager
*mgr
= pb_debug_manager(_mgr
);
354 mgr
->provider
->destroy(mgr
->provider
);
360 pb_debug_manager_create(struct pb_manager
*provider
, size_t band_size
)
362 struct pb_debug_manager
*mgr
;
367 mgr
= CALLOC_STRUCT(pb_debug_manager
);
371 mgr
->base
.destroy
= pb_debug_manager_destroy
;
372 mgr
->base
.create_buffer
= pb_debug_manager_create_buffer
;
373 mgr
->base
.flush
= pb_debug_manager_flush
;
374 mgr
->provider
= provider
;
375 mgr
->band_size
= band_size
;
385 pb_debug_manager_create(struct pb_manager
*provider
, size_t band_size
)