Merge commit 'origin/master' into gallium-0.2
[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 José Fonseca <jrfonseca@tungstengraphics.com>
33 */
34
35
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"
44
45 #include "pb_buffer.h"
46 #include "pb_bufmgr.h"
47
48
49 #ifdef DEBUG
50
51
52 /**
53 * Convenience macro (type safe).
54 */
55 #define SUPER(__derived) (&(__derived)->base)
56
57
58 struct pb_debug_manager;
59
60
61 /**
62 * Wrapper around a pipe buffer which adds delayed destruction.
63 */
64 struct pb_debug_buffer
65 {
66 struct pb_buffer base;
67
68 struct pb_buffer *buffer;
69 struct pb_debug_manager *mgr;
70
71 size_t underflow_size;
72 size_t overflow_size;
73 };
74
75
76 struct pb_debug_manager
77 {
78 struct pb_manager base;
79
80 struct pb_manager *provider;
81
82 size_t band_size;
83 };
84
85
86 static INLINE struct pb_debug_buffer *
87 pb_debug_buffer(struct pb_buffer *buf)
88 {
89 assert(buf);
90 return (struct pb_debug_buffer *)buf;
91 }
92
93
94 static INLINE struct pb_debug_manager *
95 pb_debug_manager(struct pb_manager *mgr)
96 {
97 assert(mgr);
98 return (struct pb_debug_manager *)mgr;
99 }
100
101
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
107 };
108
109
110 static INLINE void
111 fill_random_pattern(uint8_t *dst, size_t size)
112 {
113 size_t i = 0;
114 while(size--) {
115 *dst++ = random_pattern[i++];
116 i &= sizeof(random_pattern) - 1;
117 }
118 }
119
120
121 static INLINE boolean
122 check_random_pattern(const uint8_t *dst, size_t size,
123 size_t *min_ofs, size_t *max_ofs)
124 {
125 boolean result = TRUE;
126 size_t i;
127 *min_ofs = size;
128 *max_ofs = 0;
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);
133 result = FALSE;
134 }
135 }
136 return result;
137 }
138
139
140 static void
141 pb_debug_buffer_fill(struct pb_debug_buffer *buf)
142 {
143 uint8_t *map;
144
145 map = pb_map(buf->buffer, PIPE_BUFFER_USAGE_CPU_WRITE);
146 assert(map);
147 if(map) {
148 fill_random_pattern(map, buf->underflow_size);
149 fill_random_pattern(map + buf->underflow_size + buf->base.base.size,
150 buf->overflow_size);
151 pb_unmap(buf->buffer);
152 }
153 }
154
155
156 /**
157 * Check for under/over flows.
158 *
159 * Should be called with the buffer unmaped.
160 */
161 static void
162 pb_debug_buffer_check(struct pb_debug_buffer *buf)
163 {
164 uint8_t *map;
165
166 map = pb_map(buf->buffer, PIPE_BUFFER_USAGE_CPU_READ);
167 assert(map);
168 if(map) {
169 boolean underflow, overflow;
170 size_t min_ofs, max_ofs;
171
172 underflow = !check_random_pattern(map, buf->underflow_size,
173 &min_ofs, &max_ofs);
174 if(underflow) {
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);
179 }
180
181 overflow = !check_random_pattern(map + buf->underflow_size + buf->base.base.size,
182 buf->overflow_size,
183 &min_ofs, &max_ofs);
184 if(overflow) {
185 debug_printf("buffer overflow (size %u plus offset %u to %u%s bytes) detected\n",
186 buf->base.base.size,
187 min_ofs,
188 max_ofs,
189 max_ofs == buf->overflow_size - 1 ? "+" : "");
190 }
191
192 debug_assert(!underflow && !overflow);
193
194 /* re-fill if not aborted */
195 if(underflow)
196 fill_random_pattern(map, buf->underflow_size);
197 if(overflow)
198 fill_random_pattern(map + buf->underflow_size + buf->base.base.size,
199 buf->overflow_size);
200
201 pb_unmap(buf->buffer);
202 }
203 }
204
205
206 static void
207 pb_debug_buffer_destroy(struct pb_buffer *_buf)
208 {
209 struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
210
211 assert(!buf->base.base.refcount);
212
213 pb_debug_buffer_check(buf);
214
215 pb_reference(&buf->buffer, NULL);
216 FREE(buf);
217 }
218
219
220 static void *
221 pb_debug_buffer_map(struct pb_buffer *_buf,
222 unsigned flags)
223 {
224 struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
225 void *map;
226
227 pb_debug_buffer_check(buf);
228
229 map = pb_map(buf->buffer, flags);
230 if(!map)
231 return NULL;
232
233 return (uint8_t *)map + buf->underflow_size;
234 }
235
236
237 static void
238 pb_debug_buffer_unmap(struct pb_buffer *_buf)
239 {
240 struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
241 pb_unmap(buf->buffer);
242
243 pb_debug_buffer_check(buf);
244 }
245
246
247 static void
248 pb_debug_buffer_get_base_buffer(struct pb_buffer *_buf,
249 struct pb_buffer **base_buf,
250 unsigned *offset)
251 {
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;
255 }
256
257
258 const struct pb_vtbl
259 pb_debug_buffer_vtbl = {
260 pb_debug_buffer_destroy,
261 pb_debug_buffer_map,
262 pb_debug_buffer_unmap,
263 pb_debug_buffer_get_base_buffer
264 };
265
266
267 static struct pb_buffer *
268 pb_debug_manager_create_buffer(struct pb_manager *_mgr,
269 size_t size,
270 const struct pb_desc *desc)
271 {
272 struct pb_debug_manager *mgr = pb_debug_manager(_mgr);
273 struct pb_debug_buffer *buf;
274 struct pb_desc real_desc;
275 size_t real_size;
276
277 buf = CALLOC_STRUCT(pb_debug_buffer);
278 if(!buf)
279 return NULL;
280
281 real_size = size + 2*mgr->band_size;
282 real_desc = *desc;
283 real_desc.usage |= PIPE_BUFFER_USAGE_CPU_WRITE;
284 real_desc.usage |= PIPE_BUFFER_USAGE_CPU_READ;
285
286 buf->buffer = mgr->provider->create_buffer(mgr->provider,
287 real_size,
288 &real_desc);
289 if(!buf->buffer) {
290 FREE(buf);
291 return NULL;
292 }
293
294 assert(buf->buffer->base.refcount >= 1);
295 assert(pb_check_alignment(real_desc.alignment, buf->buffer->base.alignment));
296 assert(pb_check_usage(real_desc.usage, buf->buffer->base.usage));
297 assert(buf->buffer->base.size >= real_size);
298
299 buf->base.base.refcount = 1;
300 buf->base.base.alignment = desc->alignment;
301 buf->base.base.usage = desc->usage;
302 buf->base.base.size = size;
303
304 buf->base.vtbl = &pb_debug_buffer_vtbl;
305 buf->mgr = mgr;
306
307 buf->underflow_size = mgr->band_size;
308 buf->overflow_size = buf->buffer->base.size - buf->underflow_size - size;
309
310 pb_debug_buffer_fill(buf);
311
312 return &buf->base;
313 }
314
315
316 static void
317 pb_debug_manager_flush(struct pb_manager *_mgr)
318 {
319 struct pb_debug_manager *mgr = pb_debug_manager(_mgr);
320 assert(mgr->provider->flush);
321 if(mgr->provider->flush)
322 mgr->provider->flush(mgr->provider);
323 }
324
325
326 static void
327 pb_debug_manager_destroy(struct pb_manager *_mgr)
328 {
329 struct pb_debug_manager *mgr = pb_debug_manager(_mgr);
330 mgr->provider->destroy(mgr->provider);
331 FREE(mgr);
332 }
333
334
335 struct pb_manager *
336 pb_debug_manager_create(struct pb_manager *provider, size_t band_size)
337 {
338 struct pb_debug_manager *mgr;
339
340 if(!provider)
341 return NULL;
342
343 mgr = CALLOC_STRUCT(pb_debug_manager);
344 if (!mgr)
345 return NULL;
346
347 mgr->base.destroy = pb_debug_manager_destroy;
348 mgr->base.create_buffer = pb_debug_manager_create_buffer;
349 mgr->base.flush = pb_debug_manager_flush;
350 mgr->provider = provider;
351 mgr->band_size = band_size;
352
353 return &mgr->base;
354 }
355
356
357 #else /* !DEBUG */
358
359
360 struct pb_manager *
361 pb_debug_manager_create(struct pb_manager *provider, size_t band_size)
362 {
363 return provider;
364 }
365
366
367 #endif /* !DEBUG */