Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/auxiliary/pipebuffer/pb_bufmgr_debug.c
4565 views
1
/**************************************************************************
2
*
3
* Copyright 2007-2008 VMware, Inc.
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 VMWARE 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 <[email protected]>
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/list.h"
42
#include "util/u_debug_stack.h"
43
#include <inttypes.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
mtx_t 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
mtx_t 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, PB_USAGE_CPU_WRITE, NULL);
162
assert(map);
163
if (map) {
164
fill_random_pattern(map, buf->underflow_size);
165
fill_random_pattern(map + buf->underflow_size + buf->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,
183
PB_USAGE_CPU_READ |
184
PB_USAGE_UNSYNCHRONIZED, NULL);
185
assert(map);
186
if (map) {
187
boolean underflow, overflow;
188
pb_size min_ofs, max_ofs;
189
190
underflow = !check_random_pattern(map, buf->underflow_size,
191
&min_ofs, &max_ofs);
192
if(underflow) {
193
debug_printf("buffer underflow (offset -%"PRIu64"%s to -%"PRIu64" bytes) detected\n",
194
buf->underflow_size - min_ofs,
195
min_ofs == 0 ? "+" : "",
196
buf->underflow_size - max_ofs);
197
}
198
199
overflow = !check_random_pattern(map + buf->underflow_size + buf->base.size,
200
buf->overflow_size,
201
&min_ofs, &max_ofs);
202
if(overflow) {
203
debug_printf("buffer overflow (size %"PRIu64" plus offset %"PRIu64" to %"PRIu64"%s bytes) detected\n",
204
buf->base.size,
205
min_ofs,
206
max_ofs,
207
max_ofs == buf->overflow_size - 1 ? "+" : "");
208
}
209
210
if(underflow || overflow)
211
debug_backtrace_dump(buf->create_backtrace, PB_DEBUG_CREATE_BACKTRACE);
212
213
debug_assert(!underflow);
214
debug_assert(!overflow);
215
216
/* re-fill if not aborted */
217
if(underflow)
218
fill_random_pattern(map, buf->underflow_size);
219
if(overflow)
220
fill_random_pattern(map + buf->underflow_size + buf->base.size,
221
buf->overflow_size);
222
223
pb_unmap(buf->buffer);
224
}
225
}
226
227
228
static void
229
pb_debug_buffer_destroy(void *winsys, struct pb_buffer *_buf)
230
{
231
struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
232
struct pb_debug_manager *mgr = buf->mgr;
233
234
assert(!pipe_is_referenced(&buf->base.reference));
235
236
pb_debug_buffer_check(buf);
237
238
mtx_lock(&mgr->mutex);
239
list_del(&buf->head);
240
mtx_unlock(&mgr->mutex);
241
242
mtx_destroy(&buf->mutex);
243
244
pb_reference(&buf->buffer, NULL);
245
FREE(buf);
246
}
247
248
249
static void *
250
pb_debug_buffer_map(struct pb_buffer *_buf,
251
enum pb_usage_flags flags, void *flush_ctx)
252
{
253
struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
254
void *map;
255
256
pb_debug_buffer_check(buf);
257
258
map = pb_map(buf->buffer, flags, flush_ctx);
259
if (!map)
260
return NULL;
261
262
mtx_lock(&buf->mutex);
263
++buf->map_count;
264
debug_backtrace_capture(buf->map_backtrace, 1, PB_DEBUG_MAP_BACKTRACE);
265
mtx_unlock(&buf->mutex);
266
267
return (uint8_t *)map + buf->underflow_size;
268
}
269
270
271
static void
272
pb_debug_buffer_unmap(struct pb_buffer *_buf)
273
{
274
struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
275
276
mtx_lock(&buf->mutex);
277
assert(buf->map_count);
278
if(buf->map_count)
279
--buf->map_count;
280
mtx_unlock(&buf->mutex);
281
282
pb_unmap(buf->buffer);
283
284
pb_debug_buffer_check(buf);
285
}
286
287
288
static void
289
pb_debug_buffer_get_base_buffer(struct pb_buffer *_buf,
290
struct pb_buffer **base_buf,
291
pb_size *offset)
292
{
293
struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
294
pb_get_base_buffer(buf->buffer, base_buf, offset);
295
*offset += buf->underflow_size;
296
}
297
298
299
static enum pipe_error
300
pb_debug_buffer_validate(struct pb_buffer *_buf,
301
struct pb_validate *vl,
302
enum pb_usage_flags flags)
303
{
304
struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
305
306
assert((flags & ~PB_USAGE_ALL) == 0);
307
308
mtx_lock(&buf->mutex);
309
if(buf->map_count) {
310
debug_printf("%s: attempting to validate a mapped buffer\n", __FUNCTION__);
311
debug_printf("last map backtrace is\n");
312
debug_backtrace_dump(buf->map_backtrace, PB_DEBUG_MAP_BACKTRACE);
313
}
314
mtx_unlock(&buf->mutex);
315
316
pb_debug_buffer_check(buf);
317
318
return pb_validate(buf->buffer, vl, flags);
319
}
320
321
322
static void
323
pb_debug_buffer_fence(struct pb_buffer *_buf,
324
struct pipe_fence_handle *fence)
325
{
326
struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
327
pb_fence(buf->buffer, fence);
328
}
329
330
331
const struct pb_vtbl
332
pb_debug_buffer_vtbl = {
333
pb_debug_buffer_destroy,
334
pb_debug_buffer_map,
335
pb_debug_buffer_unmap,
336
pb_debug_buffer_validate,
337
pb_debug_buffer_fence,
338
pb_debug_buffer_get_base_buffer
339
};
340
341
342
static void
343
pb_debug_manager_dump_locked(struct pb_debug_manager *mgr)
344
{
345
struct list_head *curr, *next;
346
struct pb_debug_buffer *buf;
347
348
curr = mgr->list.next;
349
next = curr->next;
350
while(curr != &mgr->list) {
351
buf = LIST_ENTRY(struct pb_debug_buffer, curr, head);
352
353
debug_printf("buffer = %p\n", (void *) buf);
354
debug_printf(" .size = 0x%"PRIx64"\n", buf->base.size);
355
debug_backtrace_dump(buf->create_backtrace, PB_DEBUG_CREATE_BACKTRACE);
356
357
curr = next;
358
next = curr->next;
359
}
360
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 |= PB_USAGE_CPU_WRITE;
384
real_desc.usage |= PB_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
mtx_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_locked(mgr);
396
mtx_unlock(&mgr->mutex);
397
#endif
398
return NULL;
399
}
400
401
assert(pipe_is_referenced(&buf->buffer->reference));
402
assert(pb_check_alignment(real_desc.alignment, 1u << buf->buffer->alignment_log2));
403
assert(pb_check_usage(real_desc.usage, buf->buffer->usage));
404
assert(buf->buffer->size >= real_size);
405
406
pipe_reference_init(&buf->base.reference, 1);
407
buf->base.alignment_log2 = util_logbase2(desc->alignment);
408
buf->base.usage = desc->usage;
409
buf->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->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
(void) mtx_init(&buf->mutex, mtx_plain);
422
423
mtx_lock(&mgr->mutex);
424
list_addtail(&buf->head, &mgr->list);
425
mtx_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
mtx_lock(&mgr->mutex);
447
if(!list_is_empty(&mgr->list)) {
448
debug_printf("%s: unfreed buffers\n", __FUNCTION__);
449
pb_debug_manager_dump_locked(mgr);
450
}
451
mtx_unlock(&mgr->mutex);
452
453
mtx_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
(void) mtx_init(&mgr->mutex, mtx_plain);
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 */
498
499