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