Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/auxiliary/driver_ddebug/dd_draw.c
4561 views
1
/**************************************************************************
2
*
3
* Copyright 2015 Advanced Micro Devices, Inc.
4
* Copyright 2008 VMware, Inc.
5
* All Rights Reserved.
6
*
7
* Permission is hereby granted, free of charge, to any person obtaining a
8
* copy of this software and associated documentation files (the "Software"),
9
* to deal in the Software without restriction, including without limitation
10
* on the rights to use, copy, modify, merge, publish, distribute, sub
11
* license, and/or sell copies of the Software, and to permit persons to whom
12
* the Software is furnished to do so, subject to the following conditions:
13
*
14
* The above copyright notice and this permission notice (including the next
15
* paragraph) shall be included in all copies or substantial portions of the
16
* Software.
17
*
18
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21
* THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
22
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24
* USE OR OTHER DEALINGS IN THE SOFTWARE.
25
*
26
**************************************************************************/
27
28
#include "dd_pipe.h"
29
30
#include "util/u_dump.h"
31
#include "util/format/u_format.h"
32
#include "util/u_framebuffer.h"
33
#include "util/u_helpers.h"
34
#include "util/u_inlines.h"
35
#include "util/u_memory.h"
36
#include "util/u_process.h"
37
#include "tgsi/tgsi_parse.h"
38
#include "tgsi/tgsi_scan.h"
39
#include "util/os_time.h"
40
#include <inttypes.h>
41
#include "pipe/p_config.h"
42
43
void
44
dd_get_debug_filename_and_mkdir(char *buf, size_t buflen, bool verbose)
45
{
46
static unsigned index;
47
char proc_name[128], dir[256];
48
49
if (!os_get_process_name(proc_name, sizeof(proc_name))) {
50
fprintf(stderr, "dd: can't get the process name\n");
51
strcpy(proc_name, "unknown");
52
}
53
54
snprintf(dir, sizeof(dir), "%s/"DD_DIR, debug_get_option("HOME", "."));
55
56
if (mkdir(dir, 0774) && errno != EEXIST)
57
fprintf(stderr, "dd: can't create a directory (%i)\n", errno);
58
59
snprintf(buf, buflen, "%s/%s_%u_%08u", dir, proc_name, (unsigned int)getpid(),
60
(unsigned int)p_atomic_inc_return(&index) - 1);
61
62
if (verbose)
63
fprintf(stderr, "dd: dumping to file %s\n", buf);
64
}
65
66
FILE *
67
dd_get_debug_file(bool verbose)
68
{
69
char name[512];
70
FILE *f;
71
72
dd_get_debug_filename_and_mkdir(name, sizeof(name), verbose);
73
f = fopen(name, "w");
74
if (!f) {
75
fprintf(stderr, "dd: can't open file %s\n", name);
76
return NULL;
77
}
78
79
return f;
80
}
81
82
void
83
dd_parse_apitrace_marker(const char *string, int len, unsigned *call_number)
84
{
85
unsigned num;
86
char *s;
87
88
if (len <= 0)
89
return;
90
91
/* Make it zero-terminated. */
92
s = alloca(len + 1);
93
memcpy(s, string, len);
94
s[len] = 0;
95
96
/* Parse the number. */
97
errno = 0;
98
num = strtol(s, NULL, 10);
99
if (errno)
100
return;
101
102
*call_number = num;
103
}
104
105
void
106
dd_write_header(FILE *f, struct pipe_screen *screen, unsigned apitrace_call_number)
107
{
108
char cmd_line[4096];
109
if (os_get_command_line(cmd_line, sizeof(cmd_line)))
110
fprintf(f, "Command: %s\n", cmd_line);
111
fprintf(f, "Driver vendor: %s\n", screen->get_vendor(screen));
112
fprintf(f, "Device vendor: %s\n", screen->get_device_vendor(screen));
113
fprintf(f, "Device name: %s\n\n", screen->get_name(screen));
114
115
if (apitrace_call_number)
116
fprintf(f, "Last apitrace call: %u\n\n", apitrace_call_number);
117
}
118
119
FILE *
120
dd_get_file_stream(struct dd_screen *dscreen, unsigned apitrace_call_number)
121
{
122
struct pipe_screen *screen = dscreen->screen;
123
124
FILE *f = dd_get_debug_file(dscreen->verbose);
125
if (!f)
126
return NULL;
127
128
dd_write_header(f, screen, apitrace_call_number);
129
return f;
130
}
131
132
static void
133
dd_dump_dmesg(FILE *f)
134
{
135
#ifdef PIPE_OS_LINUX
136
char line[2000];
137
FILE *p = popen("dmesg | tail -n60", "r");
138
139
if (!p)
140
return;
141
142
fprintf(f, "\nLast 60 lines of dmesg:\n\n");
143
while (fgets(line, sizeof(line), p))
144
fputs(line, f);
145
146
pclose(p);
147
#endif
148
}
149
150
static unsigned
151
dd_num_active_viewports(struct dd_draw_state *dstate)
152
{
153
struct tgsi_shader_info info;
154
const struct tgsi_token *tokens;
155
156
if (dstate->shaders[PIPE_SHADER_GEOMETRY])
157
tokens = dstate->shaders[PIPE_SHADER_GEOMETRY]->state.shader.tokens;
158
else if (dstate->shaders[PIPE_SHADER_TESS_EVAL])
159
tokens = dstate->shaders[PIPE_SHADER_TESS_EVAL]->state.shader.tokens;
160
else if (dstate->shaders[PIPE_SHADER_VERTEX])
161
tokens = dstate->shaders[PIPE_SHADER_VERTEX]->state.shader.tokens;
162
else
163
return 1;
164
165
if (tokens) {
166
tgsi_scan_shader(tokens, &info);
167
if (info.writes_viewport_index)
168
return PIPE_MAX_VIEWPORTS;
169
}
170
171
return 1;
172
}
173
174
#define COLOR_RESET "\033[0m"
175
#define COLOR_SHADER "\033[1;32m"
176
#define COLOR_STATE "\033[1;33m"
177
178
#define DUMP(name, var) do { \
179
fprintf(f, COLOR_STATE #name ": " COLOR_RESET); \
180
util_dump_##name(f, var); \
181
fprintf(f, "\n"); \
182
} while(0)
183
184
#define DUMP_I(name, var, i) do { \
185
fprintf(f, COLOR_STATE #name " %i: " COLOR_RESET, i); \
186
util_dump_##name(f, var); \
187
fprintf(f, "\n"); \
188
} while(0)
189
190
#define DUMP_M(name, var, member) do { \
191
fprintf(f, " " #member ": "); \
192
util_dump_##name(f, (var)->member); \
193
fprintf(f, "\n"); \
194
} while(0)
195
196
#define DUMP_M_ADDR(name, var, member) do { \
197
fprintf(f, " " #member ": "); \
198
util_dump_##name(f, &(var)->member); \
199
fprintf(f, "\n"); \
200
} while(0)
201
202
#define PRINT_NAMED(type, name, value) \
203
do { \
204
fprintf(f, COLOR_STATE "%s" COLOR_RESET " = ", name); \
205
util_dump_##type(f, value); \
206
fprintf(f, "\n"); \
207
} while (0)
208
209
static void
210
util_dump_uint(FILE *f, unsigned i)
211
{
212
fprintf(f, "%u", i);
213
}
214
215
static void
216
util_dump_int(FILE *f, int i)
217
{
218
fprintf(f, "%d", i);
219
}
220
221
static void
222
util_dump_hex(FILE *f, unsigned i)
223
{
224
fprintf(f, "0x%x", i);
225
}
226
227
static void
228
util_dump_double(FILE *f, double d)
229
{
230
fprintf(f, "%f", d);
231
}
232
233
static void
234
util_dump_format(FILE *f, enum pipe_format format)
235
{
236
fprintf(f, "%s", util_format_name(format));
237
}
238
239
static void
240
util_dump_color_union(FILE *f, const union pipe_color_union *color)
241
{
242
fprintf(f, "{f = {%f, %f, %f, %f}, ui = {%u, %u, %u, %u}",
243
color->f[0], color->f[1], color->f[2], color->f[3],
244
color->ui[0], color->ui[1], color->ui[2], color->ui[3]);
245
}
246
247
static void
248
dd_dump_render_condition(struct dd_draw_state *dstate, FILE *f)
249
{
250
if (dstate->render_cond.query) {
251
fprintf(f, "render condition:\n");
252
DUMP_M(query_type, &dstate->render_cond, query->type);
253
DUMP_M(uint, &dstate->render_cond, condition);
254
DUMP_M(uint, &dstate->render_cond, mode);
255
fprintf(f, "\n");
256
}
257
}
258
259
static void
260
dd_dump_shader(struct dd_draw_state *dstate, enum pipe_shader_type sh, FILE *f)
261
{
262
int i;
263
const char *shader_str[PIPE_SHADER_TYPES];
264
265
shader_str[PIPE_SHADER_VERTEX] = "VERTEX";
266
shader_str[PIPE_SHADER_TESS_CTRL] = "TESS_CTRL";
267
shader_str[PIPE_SHADER_TESS_EVAL] = "TESS_EVAL";
268
shader_str[PIPE_SHADER_GEOMETRY] = "GEOMETRY";
269
shader_str[PIPE_SHADER_FRAGMENT] = "FRAGMENT";
270
shader_str[PIPE_SHADER_COMPUTE] = "COMPUTE";
271
272
if (sh == PIPE_SHADER_TESS_CTRL &&
273
!dstate->shaders[PIPE_SHADER_TESS_CTRL] &&
274
dstate->shaders[PIPE_SHADER_TESS_EVAL])
275
fprintf(f, "tess_state: {default_outer_level = {%f, %f, %f, %f}, "
276
"default_inner_level = {%f, %f}}\n",
277
dstate->tess_default_levels[0],
278
dstate->tess_default_levels[1],
279
dstate->tess_default_levels[2],
280
dstate->tess_default_levels[3],
281
dstate->tess_default_levels[4],
282
dstate->tess_default_levels[5]);
283
284
if (sh == PIPE_SHADER_FRAGMENT)
285
if (dstate->rs) {
286
unsigned num_viewports = dd_num_active_viewports(dstate);
287
288
if (dstate->rs->state.rs.clip_plane_enable)
289
DUMP(clip_state, &dstate->clip_state);
290
291
for (i = 0; i < num_viewports; i++)
292
DUMP_I(viewport_state, &dstate->viewports[i], i);
293
294
if (dstate->rs->state.rs.scissor)
295
for (i = 0; i < num_viewports; i++)
296
DUMP_I(scissor_state, &dstate->scissors[i], i);
297
298
DUMP(rasterizer_state, &dstate->rs->state.rs);
299
300
if (dstate->rs->state.rs.poly_stipple_enable)
301
DUMP(poly_stipple, &dstate->polygon_stipple);
302
fprintf(f, "\n");
303
}
304
305
if (!dstate->shaders[sh])
306
return;
307
308
fprintf(f, COLOR_SHADER "begin shader: %s" COLOR_RESET "\n", shader_str[sh]);
309
DUMP(shader_state, &dstate->shaders[sh]->state.shader);
310
311
for (i = 0; i < PIPE_MAX_CONSTANT_BUFFERS; i++)
312
if (dstate->constant_buffers[sh][i].buffer ||
313
dstate->constant_buffers[sh][i].user_buffer) {
314
DUMP_I(constant_buffer, &dstate->constant_buffers[sh][i], i);
315
if (dstate->constant_buffers[sh][i].buffer)
316
DUMP_M(resource, &dstate->constant_buffers[sh][i], buffer);
317
}
318
319
for (i = 0; i < PIPE_MAX_SAMPLERS; i++)
320
if (dstate->sampler_states[sh][i])
321
DUMP_I(sampler_state, &dstate->sampler_states[sh][i]->state.sampler, i);
322
323
for (i = 0; i < PIPE_MAX_SAMPLERS; i++)
324
if (dstate->sampler_views[sh][i]) {
325
DUMP_I(sampler_view, dstate->sampler_views[sh][i], i);
326
DUMP_M(resource, dstate->sampler_views[sh][i], texture);
327
}
328
329
for (i = 0; i < PIPE_MAX_SHADER_IMAGES; i++)
330
if (dstate->shader_images[sh][i].resource) {
331
DUMP_I(image_view, &dstate->shader_images[sh][i], i);
332
if (dstate->shader_images[sh][i].resource)
333
DUMP_M(resource, &dstate->shader_images[sh][i], resource);
334
}
335
336
for (i = 0; i < PIPE_MAX_SHADER_BUFFERS; i++)
337
if (dstate->shader_buffers[sh][i].buffer) {
338
DUMP_I(shader_buffer, &dstate->shader_buffers[sh][i], i);
339
if (dstate->shader_buffers[sh][i].buffer)
340
DUMP_M(resource, &dstate->shader_buffers[sh][i], buffer);
341
}
342
343
fprintf(f, COLOR_SHADER "end shader: %s" COLOR_RESET "\n\n", shader_str[sh]);
344
}
345
346
static void
347
dd_dump_flush(struct dd_draw_state *dstate, struct call_flush *info, FILE *f)
348
{
349
fprintf(f, "%s:\n", __func__+8);
350
DUMP_M(hex, info, flags);
351
}
352
353
static void
354
dd_dump_draw_vbo(struct dd_draw_state *dstate, struct pipe_draw_info *info,
355
unsigned drawid_offset,
356
const struct pipe_draw_indirect_info *indirect,
357
const struct pipe_draw_start_count_bias *draw, FILE *f)
358
{
359
int sh, i;
360
361
DUMP(draw_info, info);
362
PRINT_NAMED(int, "drawid offset", drawid_offset);
363
DUMP(draw_start_count_bias, draw);
364
if (indirect) {
365
if (indirect->buffer)
366
DUMP_M(resource, indirect, buffer);
367
if (indirect->indirect_draw_count)
368
DUMP_M(resource, indirect, indirect_draw_count);
369
if (indirect->count_from_stream_output)
370
DUMP_M(stream_output_target, indirect, count_from_stream_output);
371
}
372
373
fprintf(f, "\n");
374
375
/* TODO: dump active queries */
376
377
dd_dump_render_condition(dstate, f);
378
379
for (i = 0; i < PIPE_MAX_ATTRIBS; i++)
380
if (dstate->vertex_buffers[i].buffer.resource) {
381
DUMP_I(vertex_buffer, &dstate->vertex_buffers[i], i);
382
if (!dstate->vertex_buffers[i].is_user_buffer)
383
DUMP_M(resource, &dstate->vertex_buffers[i], buffer.resource);
384
}
385
386
if (dstate->velems) {
387
PRINT_NAMED(uint, "num vertex elements",
388
dstate->velems->state.velems.count);
389
for (i = 0; i < dstate->velems->state.velems.count; i++) {
390
fprintf(f, " ");
391
DUMP_I(vertex_element, &dstate->velems->state.velems.velems[i], i);
392
}
393
}
394
395
PRINT_NAMED(uint, "num stream output targets", dstate->num_so_targets);
396
for (i = 0; i < dstate->num_so_targets; i++)
397
if (dstate->so_targets[i]) {
398
DUMP_I(stream_output_target, dstate->so_targets[i], i);
399
DUMP_M(resource, dstate->so_targets[i], buffer);
400
fprintf(f, " offset = %i\n", dstate->so_offsets[i]);
401
}
402
403
fprintf(f, "\n");
404
for (sh = 0; sh < PIPE_SHADER_TYPES; sh++) {
405
if (sh == PIPE_SHADER_COMPUTE)
406
continue;
407
408
dd_dump_shader(dstate, sh, f);
409
}
410
411
if (dstate->dsa)
412
DUMP(depth_stencil_alpha_state, &dstate->dsa->state.dsa);
413
DUMP(stencil_ref, &dstate->stencil_ref);
414
415
if (dstate->blend)
416
DUMP(blend_state, &dstate->blend->state.blend);
417
DUMP(blend_color, &dstate->blend_color);
418
419
PRINT_NAMED(uint, "min_samples", dstate->min_samples);
420
PRINT_NAMED(hex, "sample_mask", dstate->sample_mask);
421
fprintf(f, "\n");
422
423
DUMP(framebuffer_state, &dstate->framebuffer_state);
424
for (i = 0; i < dstate->framebuffer_state.nr_cbufs; i++)
425
if (dstate->framebuffer_state.cbufs[i]) {
426
fprintf(f, " " COLOR_STATE "cbufs[%i]:" COLOR_RESET "\n ", i);
427
DUMP(surface, dstate->framebuffer_state.cbufs[i]);
428
fprintf(f, " ");
429
DUMP(resource, dstate->framebuffer_state.cbufs[i]->texture);
430
}
431
if (dstate->framebuffer_state.zsbuf) {
432
fprintf(f, " " COLOR_STATE "zsbuf:" COLOR_RESET "\n ");
433
DUMP(surface, dstate->framebuffer_state.zsbuf);
434
fprintf(f, " ");
435
DUMP(resource, dstate->framebuffer_state.zsbuf->texture);
436
}
437
fprintf(f, "\n");
438
}
439
440
static void
441
dd_dump_launch_grid(struct dd_draw_state *dstate, struct pipe_grid_info *info, FILE *f)
442
{
443
fprintf(f, "%s:\n", __func__+8);
444
DUMP(grid_info, info);
445
fprintf(f, "\n");
446
447
dd_dump_shader(dstate, PIPE_SHADER_COMPUTE, f);
448
fprintf(f, "\n");
449
}
450
451
static void
452
dd_dump_resource_copy_region(struct dd_draw_state *dstate,
453
struct call_resource_copy_region *info,
454
FILE *f)
455
{
456
fprintf(f, "%s:\n", __func__+8);
457
DUMP_M(resource, info, dst);
458
DUMP_M(uint, info, dst_level);
459
DUMP_M(uint, info, dstx);
460
DUMP_M(uint, info, dsty);
461
DUMP_M(uint, info, dstz);
462
DUMP_M(resource, info, src);
463
DUMP_M(uint, info, src_level);
464
DUMP_M_ADDR(box, info, src_box);
465
}
466
467
static void
468
dd_dump_blit(struct dd_draw_state *dstate, struct pipe_blit_info *info, FILE *f)
469
{
470
fprintf(f, "%s:\n", __func__+8);
471
DUMP_M(resource, info, dst.resource);
472
DUMP_M(uint, info, dst.level);
473
DUMP_M_ADDR(box, info, dst.box);
474
DUMP_M(format, info, dst.format);
475
476
DUMP_M(resource, info, src.resource);
477
DUMP_M(uint, info, src.level);
478
DUMP_M_ADDR(box, info, src.box);
479
DUMP_M(format, info, src.format);
480
481
DUMP_M(hex, info, mask);
482
DUMP_M(uint, info, filter);
483
DUMP_M(uint, info, scissor_enable);
484
DUMP_M_ADDR(scissor_state, info, scissor);
485
DUMP_M(uint, info, render_condition_enable);
486
487
if (info->render_condition_enable)
488
dd_dump_render_condition(dstate, f);
489
}
490
491
static void
492
dd_dump_generate_mipmap(struct dd_draw_state *dstate, FILE *f)
493
{
494
fprintf(f, "%s:\n", __func__+8);
495
/* TODO */
496
}
497
498
static void
499
dd_dump_get_query_result_resource(struct call_get_query_result_resource *info, FILE *f)
500
{
501
fprintf(f, "%s:\n", __func__ + 8);
502
DUMP_M(query_type, info, query_type);
503
DUMP_M(uint, info, wait);
504
DUMP_M(query_value_type, info, result_type);
505
DUMP_M(int, info, index);
506
DUMP_M(resource, info, resource);
507
DUMP_M(uint, info, offset);
508
}
509
510
static void
511
dd_dump_flush_resource(struct dd_draw_state *dstate, struct pipe_resource *res,
512
FILE *f)
513
{
514
fprintf(f, "%s:\n", __func__+8);
515
DUMP(resource, res);
516
}
517
518
static void
519
dd_dump_clear(struct dd_draw_state *dstate, struct call_clear *info, FILE *f)
520
{
521
fprintf(f, "%s:\n", __func__+8);
522
DUMP_M(uint, info, buffers);
523
fprintf(f, " scissor_state: %d,%d %d,%d\n",
524
info->scissor_state.minx, info->scissor_state.miny,
525
info->scissor_state.maxx, info->scissor_state.maxy);
526
DUMP_M_ADDR(color_union, info, color);
527
DUMP_M(double, info, depth);
528
DUMP_M(hex, info, stencil);
529
}
530
531
static void
532
dd_dump_clear_buffer(struct dd_draw_state *dstate, struct call_clear_buffer *info,
533
FILE *f)
534
{
535
int i;
536
const char *value = (const char*)info->clear_value;
537
538
fprintf(f, "%s:\n", __func__+8);
539
DUMP_M(resource, info, res);
540
DUMP_M(uint, info, offset);
541
DUMP_M(uint, info, size);
542
DUMP_M(uint, info, clear_value_size);
543
544
fprintf(f, " clear_value:");
545
for (i = 0; i < info->clear_value_size; i++)
546
fprintf(f, " %02x", value[i]);
547
fprintf(f, "\n");
548
}
549
550
static void
551
dd_dump_transfer_map(struct call_transfer_map *info, FILE *f)
552
{
553
fprintf(f, "%s:\n", __func__+8);
554
DUMP_M_ADDR(transfer, info, transfer);
555
DUMP_M(ptr, info, transfer_ptr);
556
DUMP_M(ptr, info, ptr);
557
}
558
559
static void
560
dd_dump_transfer_flush_region(struct call_transfer_flush_region *info, FILE *f)
561
{
562
fprintf(f, "%s:\n", __func__+8);
563
DUMP_M_ADDR(transfer, info, transfer);
564
DUMP_M(ptr, info, transfer_ptr);
565
DUMP_M_ADDR(box, info, box);
566
}
567
568
static void
569
dd_dump_transfer_unmap(struct call_transfer_unmap *info, FILE *f)
570
{
571
fprintf(f, "%s:\n", __func__+8);
572
DUMP_M_ADDR(transfer, info, transfer);
573
DUMP_M(ptr, info, transfer_ptr);
574
}
575
576
static void
577
dd_dump_buffer_subdata(struct call_buffer_subdata *info, FILE *f)
578
{
579
fprintf(f, "%s:\n", __func__+8);
580
DUMP_M(resource, info, resource);
581
DUMP_M(transfer_usage, info, usage);
582
DUMP_M(uint, info, offset);
583
DUMP_M(uint, info, size);
584
DUMP_M(ptr, info, data);
585
}
586
587
static void
588
dd_dump_texture_subdata(struct call_texture_subdata *info, FILE *f)
589
{
590
fprintf(f, "%s:\n", __func__+8);
591
DUMP_M(resource, info, resource);
592
DUMP_M(uint, info, level);
593
DUMP_M(transfer_usage, info, usage);
594
DUMP_M_ADDR(box, info, box);
595
DUMP_M(ptr, info, data);
596
DUMP_M(uint, info, stride);
597
DUMP_M(uint, info, layer_stride);
598
}
599
600
static void
601
dd_dump_clear_texture(struct dd_draw_state *dstate, FILE *f)
602
{
603
fprintf(f, "%s:\n", __func__+8);
604
/* TODO */
605
}
606
607
static void
608
dd_dump_clear_render_target(struct dd_draw_state *dstate, FILE *f)
609
{
610
fprintf(f, "%s:\n", __func__+8);
611
/* TODO */
612
}
613
614
static void
615
dd_dump_clear_depth_stencil(struct dd_draw_state *dstate, FILE *f)
616
{
617
fprintf(f, "%s:\n", __func__+8);
618
/* TODO */
619
}
620
621
static void
622
dd_dump_driver_state(struct dd_context *dctx, FILE *f, unsigned flags)
623
{
624
if (dctx->pipe->dump_debug_state) {
625
fprintf(f,"\n\n**************************************************"
626
"***************************\n");
627
fprintf(f, "Driver-specific state:\n\n");
628
dctx->pipe->dump_debug_state(dctx->pipe, f, flags);
629
}
630
}
631
632
static void
633
dd_dump_call(FILE *f, struct dd_draw_state *state, struct dd_call *call)
634
{
635
switch (call->type) {
636
case CALL_FLUSH:
637
dd_dump_flush(state, &call->info.flush, f);
638
break;
639
case CALL_DRAW_VBO:
640
dd_dump_draw_vbo(state, &call->info.draw_vbo.info,
641
call->info.draw_vbo.drawid_offset,
642
&call->info.draw_vbo.indirect,
643
&call->info.draw_vbo.draw, f);
644
break;
645
case CALL_LAUNCH_GRID:
646
dd_dump_launch_grid(state, &call->info.launch_grid, f);
647
break;
648
case CALL_RESOURCE_COPY_REGION:
649
dd_dump_resource_copy_region(state,
650
&call->info.resource_copy_region, f);
651
break;
652
case CALL_BLIT:
653
dd_dump_blit(state, &call->info.blit, f);
654
break;
655
case CALL_FLUSH_RESOURCE:
656
dd_dump_flush_resource(state, call->info.flush_resource, f);
657
break;
658
case CALL_CLEAR:
659
dd_dump_clear(state, &call->info.clear, f);
660
break;
661
case CALL_CLEAR_BUFFER:
662
dd_dump_clear_buffer(state, &call->info.clear_buffer, f);
663
break;
664
case CALL_CLEAR_TEXTURE:
665
dd_dump_clear_texture(state, f);
666
break;
667
case CALL_CLEAR_RENDER_TARGET:
668
dd_dump_clear_render_target(state, f);
669
break;
670
case CALL_CLEAR_DEPTH_STENCIL:
671
dd_dump_clear_depth_stencil(state, f);
672
break;
673
case CALL_GENERATE_MIPMAP:
674
dd_dump_generate_mipmap(state, f);
675
break;
676
case CALL_GET_QUERY_RESULT_RESOURCE:
677
dd_dump_get_query_result_resource(&call->info.get_query_result_resource, f);
678
break;
679
case CALL_TRANSFER_MAP:
680
dd_dump_transfer_map(&call->info.transfer_map, f);
681
break;
682
case CALL_TRANSFER_FLUSH_REGION:
683
dd_dump_transfer_flush_region(&call->info.transfer_flush_region, f);
684
break;
685
case CALL_TRANSFER_UNMAP:
686
dd_dump_transfer_unmap(&call->info.transfer_unmap, f);
687
break;
688
case CALL_BUFFER_SUBDATA:
689
dd_dump_buffer_subdata(&call->info.buffer_subdata, f);
690
break;
691
case CALL_TEXTURE_SUBDATA:
692
dd_dump_texture_subdata(&call->info.texture_subdata, f);
693
break;
694
}
695
}
696
697
static void
698
dd_kill_process(void)
699
{
700
#ifdef PIPE_OS_UNIX
701
sync();
702
#endif
703
fprintf(stderr, "dd: Aborting the process...\n");
704
fflush(stdout);
705
fflush(stderr);
706
exit(1);
707
}
708
709
static void
710
dd_unreference_copy_of_call(struct dd_call *dst)
711
{
712
switch (dst->type) {
713
case CALL_FLUSH:
714
break;
715
case CALL_DRAW_VBO:
716
pipe_so_target_reference(&dst->info.draw_vbo.indirect.count_from_stream_output, NULL);
717
pipe_resource_reference(&dst->info.draw_vbo.indirect.buffer, NULL);
718
pipe_resource_reference(&dst->info.draw_vbo.indirect.indirect_draw_count, NULL);
719
if (dst->info.draw_vbo.info.index_size &&
720
!dst->info.draw_vbo.info.has_user_indices)
721
pipe_resource_reference(&dst->info.draw_vbo.info.index.resource, NULL);
722
else
723
dst->info.draw_vbo.info.index.user = NULL;
724
break;
725
case CALL_LAUNCH_GRID:
726
pipe_resource_reference(&dst->info.launch_grid.indirect, NULL);
727
break;
728
case CALL_RESOURCE_COPY_REGION:
729
pipe_resource_reference(&dst->info.resource_copy_region.dst, NULL);
730
pipe_resource_reference(&dst->info.resource_copy_region.src, NULL);
731
break;
732
case CALL_BLIT:
733
pipe_resource_reference(&dst->info.blit.dst.resource, NULL);
734
pipe_resource_reference(&dst->info.blit.src.resource, NULL);
735
break;
736
case CALL_FLUSH_RESOURCE:
737
pipe_resource_reference(&dst->info.flush_resource, NULL);
738
break;
739
case CALL_CLEAR:
740
break;
741
case CALL_CLEAR_BUFFER:
742
pipe_resource_reference(&dst->info.clear_buffer.res, NULL);
743
break;
744
case CALL_CLEAR_TEXTURE:
745
break;
746
case CALL_CLEAR_RENDER_TARGET:
747
break;
748
case CALL_CLEAR_DEPTH_STENCIL:
749
break;
750
case CALL_GENERATE_MIPMAP:
751
pipe_resource_reference(&dst->info.generate_mipmap.res, NULL);
752
break;
753
case CALL_GET_QUERY_RESULT_RESOURCE:
754
pipe_resource_reference(&dst->info.get_query_result_resource.resource, NULL);
755
break;
756
case CALL_TRANSFER_MAP:
757
pipe_resource_reference(&dst->info.transfer_map.transfer.resource, NULL);
758
break;
759
case CALL_TRANSFER_FLUSH_REGION:
760
pipe_resource_reference(&dst->info.transfer_flush_region.transfer.resource, NULL);
761
break;
762
case CALL_TRANSFER_UNMAP:
763
pipe_resource_reference(&dst->info.transfer_unmap.transfer.resource, NULL);
764
break;
765
case CALL_BUFFER_SUBDATA:
766
pipe_resource_reference(&dst->info.buffer_subdata.resource, NULL);
767
break;
768
case CALL_TEXTURE_SUBDATA:
769
pipe_resource_reference(&dst->info.texture_subdata.resource, NULL);
770
break;
771
}
772
}
773
774
static void
775
dd_init_copy_of_draw_state(struct dd_draw_state_copy *state)
776
{
777
unsigned i,j;
778
779
/* Just clear pointers to gallium objects. Don't clear the whole structure,
780
* because it would kill performance with its size of 130 KB.
781
*/
782
memset(state->base.vertex_buffers, 0,
783
sizeof(state->base.vertex_buffers));
784
memset(state->base.so_targets, 0,
785
sizeof(state->base.so_targets));
786
memset(state->base.constant_buffers, 0,
787
sizeof(state->base.constant_buffers));
788
memset(state->base.sampler_views, 0,
789
sizeof(state->base.sampler_views));
790
memset(state->base.shader_images, 0,
791
sizeof(state->base.shader_images));
792
memset(state->base.shader_buffers, 0,
793
sizeof(state->base.shader_buffers));
794
memset(&state->base.framebuffer_state, 0,
795
sizeof(state->base.framebuffer_state));
796
797
memset(state->shaders, 0, sizeof(state->shaders));
798
799
state->base.render_cond.query = &state->render_cond;
800
801
for (i = 0; i < PIPE_SHADER_TYPES; i++) {
802
state->base.shaders[i] = &state->shaders[i];
803
for (j = 0; j < PIPE_MAX_SAMPLERS; j++)
804
state->base.sampler_states[i][j] = &state->sampler_states[i][j];
805
}
806
807
state->base.velems = &state->velems;
808
state->base.rs = &state->rs;
809
state->base.dsa = &state->dsa;
810
state->base.blend = &state->blend;
811
}
812
813
static void
814
dd_unreference_copy_of_draw_state(struct dd_draw_state_copy *state)
815
{
816
struct dd_draw_state *dst = &state->base;
817
unsigned i,j;
818
819
for (i = 0; i < ARRAY_SIZE(dst->vertex_buffers); i++)
820
pipe_vertex_buffer_unreference(&dst->vertex_buffers[i]);
821
for (i = 0; i < ARRAY_SIZE(dst->so_targets); i++)
822
pipe_so_target_reference(&dst->so_targets[i], NULL);
823
824
for (i = 0; i < PIPE_SHADER_TYPES; i++) {
825
if (dst->shaders[i])
826
tgsi_free_tokens(dst->shaders[i]->state.shader.tokens);
827
828
for (j = 0; j < PIPE_MAX_CONSTANT_BUFFERS; j++)
829
pipe_resource_reference(&dst->constant_buffers[i][j].buffer, NULL);
830
for (j = 0; j < PIPE_MAX_SAMPLERS; j++)
831
pipe_sampler_view_reference(&dst->sampler_views[i][j], NULL);
832
for (j = 0; j < PIPE_MAX_SHADER_IMAGES; j++)
833
pipe_resource_reference(&dst->shader_images[i][j].resource, NULL);
834
for (j = 0; j < PIPE_MAX_SHADER_BUFFERS; j++)
835
pipe_resource_reference(&dst->shader_buffers[i][j].buffer, NULL);
836
}
837
838
util_unreference_framebuffer_state(&dst->framebuffer_state);
839
}
840
841
static void
842
dd_copy_draw_state(struct dd_draw_state *dst, struct dd_draw_state *src)
843
{
844
unsigned i,j;
845
846
if (src->render_cond.query) {
847
*dst->render_cond.query = *src->render_cond.query;
848
dst->render_cond.condition = src->render_cond.condition;
849
dst->render_cond.mode = src->render_cond.mode;
850
} else {
851
dst->render_cond.query = NULL;
852
}
853
854
for (i = 0; i < ARRAY_SIZE(src->vertex_buffers); i++) {
855
pipe_vertex_buffer_reference(&dst->vertex_buffers[i],
856
&src->vertex_buffers[i]);
857
}
858
859
dst->num_so_targets = src->num_so_targets;
860
for (i = 0; i < src->num_so_targets; i++)
861
pipe_so_target_reference(&dst->so_targets[i], src->so_targets[i]);
862
memcpy(dst->so_offsets, src->so_offsets, sizeof(src->so_offsets));
863
864
for (i = 0; i < PIPE_SHADER_TYPES; i++) {
865
if (!src->shaders[i]) {
866
dst->shaders[i] = NULL;
867
continue;
868
}
869
870
if (src->shaders[i]) {
871
dst->shaders[i]->state.shader = src->shaders[i]->state.shader;
872
if (src->shaders[i]->state.shader.tokens) {
873
dst->shaders[i]->state.shader.tokens =
874
tgsi_dup_tokens(src->shaders[i]->state.shader.tokens);
875
} else {
876
dst->shaders[i]->state.shader.ir.nir = NULL;
877
}
878
} else {
879
dst->shaders[i] = NULL;
880
}
881
882
for (j = 0; j < PIPE_MAX_CONSTANT_BUFFERS; j++) {
883
pipe_resource_reference(&dst->constant_buffers[i][j].buffer,
884
src->constant_buffers[i][j].buffer);
885
memcpy(&dst->constant_buffers[i][j], &src->constant_buffers[i][j],
886
sizeof(src->constant_buffers[i][j]));
887
}
888
889
for (j = 0; j < PIPE_MAX_SAMPLERS; j++) {
890
pipe_sampler_view_reference(&dst->sampler_views[i][j],
891
src->sampler_views[i][j]);
892
if (src->sampler_states[i][j])
893
dst->sampler_states[i][j]->state.sampler =
894
src->sampler_states[i][j]->state.sampler;
895
else
896
dst->sampler_states[i][j] = NULL;
897
}
898
899
for (j = 0; j < PIPE_MAX_SHADER_IMAGES; j++) {
900
pipe_resource_reference(&dst->shader_images[i][j].resource,
901
src->shader_images[i][j].resource);
902
memcpy(&dst->shader_images[i][j], &src->shader_images[i][j],
903
sizeof(src->shader_images[i][j]));
904
}
905
906
for (j = 0; j < PIPE_MAX_SHADER_BUFFERS; j++) {
907
pipe_resource_reference(&dst->shader_buffers[i][j].buffer,
908
src->shader_buffers[i][j].buffer);
909
memcpy(&dst->shader_buffers[i][j], &src->shader_buffers[i][j],
910
sizeof(src->shader_buffers[i][j]));
911
}
912
}
913
914
if (src->velems)
915
dst->velems->state.velems = src->velems->state.velems;
916
else
917
dst->velems = NULL;
918
919
if (src->rs)
920
dst->rs->state.rs = src->rs->state.rs;
921
else
922
dst->rs = NULL;
923
924
if (src->dsa)
925
dst->dsa->state.dsa = src->dsa->state.dsa;
926
else
927
dst->dsa = NULL;
928
929
if (src->blend)
930
dst->blend->state.blend = src->blend->state.blend;
931
else
932
dst->blend = NULL;
933
934
dst->blend_color = src->blend_color;
935
dst->stencil_ref = src->stencil_ref;
936
dst->sample_mask = src->sample_mask;
937
dst->min_samples = src->min_samples;
938
dst->clip_state = src->clip_state;
939
util_copy_framebuffer_state(&dst->framebuffer_state, &src->framebuffer_state);
940
memcpy(dst->scissors, src->scissors, sizeof(src->scissors));
941
memcpy(dst->viewports, src->viewports, sizeof(src->viewports));
942
memcpy(dst->tess_default_levels, src->tess_default_levels,
943
sizeof(src->tess_default_levels));
944
dst->apitrace_call_number = src->apitrace_call_number;
945
}
946
947
static void
948
dd_free_record(struct pipe_screen *screen, struct dd_draw_record *record)
949
{
950
u_log_page_destroy(record->log_page);
951
dd_unreference_copy_of_call(&record->call);
952
dd_unreference_copy_of_draw_state(&record->draw_state);
953
screen->fence_reference(screen, &record->prev_bottom_of_pipe, NULL);
954
screen->fence_reference(screen, &record->top_of_pipe, NULL);
955
screen->fence_reference(screen, &record->bottom_of_pipe, NULL);
956
util_queue_fence_destroy(&record->driver_finished);
957
FREE(record);
958
}
959
960
static void
961
dd_write_record(FILE *f, struct dd_draw_record *record)
962
{
963
PRINT_NAMED(ptr, "pipe", record->dctx->pipe);
964
PRINT_NAMED(ns, "time before (API call)", record->time_before);
965
PRINT_NAMED(ns, "time after (driver done)", record->time_after);
966
fprintf(f, "\n");
967
968
dd_dump_call(f, &record->draw_state.base, &record->call);
969
970
if (record->log_page) {
971
fprintf(f,"\n\n**************************************************"
972
"***************************\n");
973
fprintf(f, "Context Log:\n\n");
974
u_log_page_print(record->log_page, f);
975
}
976
}
977
978
static void
979
dd_maybe_dump_record(struct dd_screen *dscreen, struct dd_draw_record *record)
980
{
981
if (dscreen->dump_mode == DD_DUMP_ONLY_HANGS ||
982
(dscreen->dump_mode == DD_DUMP_APITRACE_CALL &&
983
dscreen->apitrace_dump_call != record->draw_state.base.apitrace_call_number))
984
return;
985
986
char name[512];
987
dd_get_debug_filename_and_mkdir(name, sizeof(name), dscreen->verbose);
988
FILE *f = fopen(name, "w");
989
if (!f) {
990
fprintf(stderr, "dd: failed to open %s\n", name);
991
return;
992
}
993
994
dd_write_header(f, dscreen->screen, record->draw_state.base.apitrace_call_number);
995
dd_write_record(f, record);
996
997
fclose(f);
998
}
999
1000
static const char *
1001
dd_fence_state(struct pipe_screen *screen, struct pipe_fence_handle *fence,
1002
bool *not_reached)
1003
{
1004
if (!fence)
1005
return "---";
1006
1007
bool ok = screen->fence_finish(screen, NULL, fence, 0);
1008
1009
if (not_reached && !ok)
1010
*not_reached = true;
1011
1012
return ok ? "YES" : "NO ";
1013
}
1014
1015
static void
1016
dd_report_hang(struct dd_context *dctx)
1017
{
1018
struct dd_screen *dscreen = dd_screen(dctx->base.screen);
1019
struct pipe_screen *screen = dscreen->screen;
1020
bool encountered_hang = false;
1021
bool stop_output = false;
1022
unsigned num_later = 0;
1023
1024
fprintf(stderr, "GPU hang detected, collecting information...\n\n");
1025
1026
fprintf(stderr, "Draw # driver prev BOP TOP BOP dump file\n"
1027
"-------------------------------------------------------------\n");
1028
1029
list_for_each_entry(struct dd_draw_record, record, &dctx->records, list) {
1030
if (!encountered_hang &&
1031
screen->fence_finish(screen, NULL, record->bottom_of_pipe, 0)) {
1032
dd_maybe_dump_record(dscreen, record);
1033
continue;
1034
}
1035
1036
if (stop_output) {
1037
dd_maybe_dump_record(dscreen, record);
1038
num_later++;
1039
continue;
1040
}
1041
1042
bool driver = util_queue_fence_is_signalled(&record->driver_finished);
1043
bool top_not_reached = false;
1044
const char *prev_bop = dd_fence_state(screen, record->prev_bottom_of_pipe, NULL);
1045
const char *top = dd_fence_state(screen, record->top_of_pipe, &top_not_reached);
1046
const char *bop = dd_fence_state(screen, record->bottom_of_pipe, NULL);
1047
1048
fprintf(stderr, "%-9u %s %s %s %s ",
1049
record->draw_call, driver ? "YES" : "NO ", prev_bop, top, bop);
1050
1051
char name[512];
1052
dd_get_debug_filename_and_mkdir(name, sizeof(name), false);
1053
1054
FILE *f = fopen(name, "w");
1055
if (!f) {
1056
fprintf(stderr, "fopen failed\n");
1057
} else {
1058
fprintf(stderr, "%s\n", name);
1059
1060
dd_write_header(f, dscreen->screen, record->draw_state.base.apitrace_call_number);
1061
dd_write_record(f, record);
1062
1063
fclose(f);
1064
}
1065
1066
if (top_not_reached)
1067
stop_output = true;
1068
encountered_hang = true;
1069
}
1070
1071
if (num_later)
1072
fprintf(stderr, "... and %u additional draws.\n", num_later);
1073
1074
char name[512];
1075
dd_get_debug_filename_and_mkdir(name, sizeof(name), false);
1076
FILE *f = fopen(name, "w");
1077
if (!f) {
1078
fprintf(stderr, "fopen failed\n");
1079
} else {
1080
dd_write_header(f, dscreen->screen, 0);
1081
dd_dump_driver_state(dctx, f, PIPE_DUMP_DEVICE_STATUS_REGISTERS);
1082
dd_dump_dmesg(f);
1083
fclose(f);
1084
}
1085
1086
fprintf(stderr, "\nDone.\n");
1087
dd_kill_process();
1088
}
1089
1090
int
1091
dd_thread_main(void *input)
1092
{
1093
struct dd_context *dctx = (struct dd_context *)input;
1094
struct dd_screen *dscreen = dd_screen(dctx->base.screen);
1095
struct pipe_screen *screen = dscreen->screen;
1096
1097
const char *process_name = util_get_process_name();
1098
if (process_name) {
1099
char threadname[16];
1100
snprintf(threadname, sizeof(threadname), "%.*s:ddbg",
1101
(int)MIN2(strlen(process_name), sizeof(threadname) - 6),
1102
process_name);
1103
u_thread_setname(threadname);
1104
}
1105
1106
mtx_lock(&dctx->mutex);
1107
1108
for (;;) {
1109
struct list_head records;
1110
list_replace(&dctx->records, &records);
1111
list_inithead(&dctx->records);
1112
dctx->num_records = 0;
1113
1114
if (dctx->api_stalled)
1115
cnd_signal(&dctx->cond);
1116
1117
if (list_is_empty(&records)) {
1118
if (dctx->kill_thread)
1119
break;
1120
1121
cnd_wait(&dctx->cond, &dctx->mutex);
1122
continue;
1123
}
1124
1125
mtx_unlock(&dctx->mutex);
1126
1127
/* Wait for the youngest draw. This means hangs can take a bit longer
1128
* to detect, but it's more efficient this way. */
1129
struct dd_draw_record *youngest =
1130
list_last_entry(&records, struct dd_draw_record, list);
1131
1132
if (dscreen->timeout_ms > 0) {
1133
uint64_t abs_timeout = os_time_get_absolute_timeout(
1134
(uint64_t)dscreen->timeout_ms * 1000*1000);
1135
1136
if (!util_queue_fence_wait_timeout(&youngest->driver_finished, abs_timeout) ||
1137
!screen->fence_finish(screen, NULL, youngest->bottom_of_pipe,
1138
(uint64_t)dscreen->timeout_ms * 1000*1000)) {
1139
mtx_lock(&dctx->mutex);
1140
list_splice(&records, &dctx->records);
1141
dd_report_hang(dctx);
1142
/* we won't actually get here */
1143
mtx_unlock(&dctx->mutex);
1144
}
1145
} else {
1146
util_queue_fence_wait(&youngest->driver_finished);
1147
}
1148
1149
list_for_each_entry_safe(struct dd_draw_record, record, &records, list) {
1150
dd_maybe_dump_record(dscreen, record);
1151
list_del(&record->list);
1152
dd_free_record(screen, record);
1153
}
1154
1155
mtx_lock(&dctx->mutex);
1156
}
1157
mtx_unlock(&dctx->mutex);
1158
return 0;
1159
}
1160
1161
static struct dd_draw_record *
1162
dd_create_record(struct dd_context *dctx)
1163
{
1164
struct dd_draw_record *record;
1165
1166
record = MALLOC_STRUCT(dd_draw_record);
1167
if (!record)
1168
return NULL;
1169
1170
record->dctx = dctx;
1171
record->draw_call = dctx->num_draw_calls;
1172
1173
record->prev_bottom_of_pipe = NULL;
1174
record->top_of_pipe = NULL;
1175
record->bottom_of_pipe = NULL;
1176
record->log_page = NULL;
1177
util_queue_fence_init(&record->driver_finished);
1178
util_queue_fence_reset(&record->driver_finished);
1179
1180
dd_init_copy_of_draw_state(&record->draw_state);
1181
dd_copy_draw_state(&record->draw_state.base, &dctx->draw_state);
1182
1183
return record;
1184
}
1185
1186
static void
1187
dd_add_record(struct dd_context *dctx, struct dd_draw_record *record)
1188
{
1189
mtx_lock(&dctx->mutex);
1190
if (unlikely(dctx->num_records > 10000)) {
1191
dctx->api_stalled = true;
1192
/* Since this is only a heuristic to prevent the API thread from getting
1193
* too far ahead, we don't need a loop here. */
1194
cnd_wait(&dctx->cond, &dctx->mutex);
1195
dctx->api_stalled = false;
1196
}
1197
1198
if (list_is_empty(&dctx->records))
1199
cnd_signal(&dctx->cond);
1200
1201
list_addtail(&record->list, &dctx->records);
1202
dctx->num_records++;
1203
mtx_unlock(&dctx->mutex);
1204
}
1205
1206
static void
1207
dd_before_draw(struct dd_context *dctx, struct dd_draw_record *record)
1208
{
1209
struct dd_screen *dscreen = dd_screen(dctx->base.screen);
1210
struct pipe_context *pipe = dctx->pipe;
1211
struct pipe_screen *screen = dscreen->screen;
1212
1213
record->time_before = os_time_get_nano();
1214
1215
if (dscreen->timeout_ms > 0) {
1216
if (dscreen->flush_always && dctx->num_draw_calls >= dscreen->skip_count) {
1217
pipe->flush(pipe, &record->prev_bottom_of_pipe, 0);
1218
screen->fence_reference(screen, &record->top_of_pipe, record->prev_bottom_of_pipe);
1219
} else {
1220
pipe->flush(pipe, &record->prev_bottom_of_pipe,
1221
PIPE_FLUSH_DEFERRED | PIPE_FLUSH_BOTTOM_OF_PIPE);
1222
pipe->flush(pipe, &record->top_of_pipe,
1223
PIPE_FLUSH_DEFERRED | PIPE_FLUSH_TOP_OF_PIPE);
1224
}
1225
} else if (dscreen->flush_always && dctx->num_draw_calls >= dscreen->skip_count) {
1226
pipe->flush(pipe, NULL, 0);
1227
}
1228
1229
dd_add_record(dctx, record);
1230
}
1231
1232
static void
1233
dd_after_draw_async(void *data)
1234
{
1235
struct dd_draw_record *record = (struct dd_draw_record *)data;
1236
struct dd_context *dctx = record->dctx;
1237
struct dd_screen *dscreen = dd_screen(dctx->base.screen);
1238
1239
record->log_page = u_log_new_page(&dctx->log);
1240
record->time_after = os_time_get_nano();
1241
1242
util_queue_fence_signal(&record->driver_finished);
1243
1244
if (dscreen->dump_mode == DD_DUMP_APITRACE_CALL &&
1245
dscreen->apitrace_dump_call > dctx->draw_state.apitrace_call_number) {
1246
dd_thread_join(dctx);
1247
/* No need to continue. */
1248
exit(0);
1249
}
1250
}
1251
1252
static void
1253
dd_after_draw(struct dd_context *dctx, struct dd_draw_record *record)
1254
{
1255
struct dd_screen *dscreen = dd_screen(dctx->base.screen);
1256
struct pipe_context *pipe = dctx->pipe;
1257
1258
if (dscreen->timeout_ms > 0) {
1259
unsigned flush_flags;
1260
if (dscreen->flush_always && dctx->num_draw_calls >= dscreen->skip_count)
1261
flush_flags = 0;
1262
else
1263
flush_flags = PIPE_FLUSH_DEFERRED | PIPE_FLUSH_BOTTOM_OF_PIPE;
1264
pipe->flush(pipe, &record->bottom_of_pipe, flush_flags);
1265
}
1266
1267
if (pipe->callback) {
1268
pipe->callback(pipe, dd_after_draw_async, record, true);
1269
} else {
1270
dd_after_draw_async(record);
1271
}
1272
1273
++dctx->num_draw_calls;
1274
if (dscreen->skip_count && dctx->num_draw_calls % 10000 == 0)
1275
fprintf(stderr, "Gallium debugger reached %u draw calls.\n",
1276
dctx->num_draw_calls);
1277
}
1278
1279
static void
1280
dd_context_flush(struct pipe_context *_pipe,
1281
struct pipe_fence_handle **fence, unsigned flags)
1282
{
1283
struct dd_context *dctx = dd_context(_pipe);
1284
struct pipe_context *pipe = dctx->pipe;
1285
struct pipe_screen *screen = pipe->screen;
1286
struct dd_draw_record *record = dd_create_record(dctx);
1287
1288
record->call.type = CALL_FLUSH;
1289
record->call.info.flush.flags = flags;
1290
1291
record->time_before = os_time_get_nano();
1292
1293
dd_add_record(dctx, record);
1294
1295
pipe->flush(pipe, &record->bottom_of_pipe, flags);
1296
if (fence)
1297
screen->fence_reference(screen, fence, record->bottom_of_pipe);
1298
1299
if (pipe->callback) {
1300
pipe->callback(pipe, dd_after_draw_async, record, true);
1301
} else {
1302
dd_after_draw_async(record);
1303
}
1304
}
1305
1306
static void
1307
dd_context_draw_vbo(struct pipe_context *_pipe,
1308
const struct pipe_draw_info *info,
1309
unsigned drawid_offset,
1310
const struct pipe_draw_indirect_info *indirect,
1311
const struct pipe_draw_start_count_bias *draws,
1312
unsigned num_draws)
1313
{
1314
struct dd_context *dctx = dd_context(_pipe);
1315
struct pipe_context *pipe = dctx->pipe;
1316
struct dd_draw_record *record = dd_create_record(dctx);
1317
1318
record->call.type = CALL_DRAW_VBO;
1319
record->call.info.draw_vbo.info = *info;
1320
record->call.info.draw_vbo.drawid_offset = drawid_offset;
1321
record->call.info.draw_vbo.draw = draws[0];
1322
if (info->index_size && !info->has_user_indices) {
1323
record->call.info.draw_vbo.info.index.resource = NULL;
1324
pipe_resource_reference(&record->call.info.draw_vbo.info.index.resource,
1325
info->index.resource);
1326
}
1327
1328
if (indirect) {
1329
record->call.info.draw_vbo.indirect = *indirect;
1330
record->call.info.draw_vbo.indirect.buffer = NULL;
1331
pipe_resource_reference(&record->call.info.draw_vbo.indirect.buffer,
1332
indirect->buffer);
1333
record->call.info.draw_vbo.indirect.indirect_draw_count = NULL;
1334
pipe_resource_reference(&record->call.info.draw_vbo.indirect.indirect_draw_count,
1335
indirect->indirect_draw_count);
1336
record->call.info.draw_vbo.indirect.count_from_stream_output = NULL;
1337
pipe_so_target_reference(&record->call.info.draw_vbo.indirect.count_from_stream_output,
1338
indirect->count_from_stream_output);
1339
} else {
1340
memset(&record->call.info.draw_vbo.indirect, 0, sizeof(*indirect));
1341
}
1342
1343
dd_before_draw(dctx, record);
1344
pipe->draw_vbo(pipe, info, drawid_offset, indirect, draws, num_draws);
1345
dd_after_draw(dctx, record);
1346
}
1347
1348
static void
1349
dd_context_launch_grid(struct pipe_context *_pipe,
1350
const struct pipe_grid_info *info)
1351
{
1352
struct dd_context *dctx = dd_context(_pipe);
1353
struct pipe_context *pipe = dctx->pipe;
1354
struct dd_draw_record *record = dd_create_record(dctx);
1355
1356
record->call.type = CALL_LAUNCH_GRID;
1357
record->call.info.launch_grid = *info;
1358
record->call.info.launch_grid.indirect = NULL;
1359
pipe_resource_reference(&record->call.info.launch_grid.indirect, info->indirect);
1360
1361
dd_before_draw(dctx, record);
1362
pipe->launch_grid(pipe, info);
1363
dd_after_draw(dctx, record);
1364
}
1365
1366
static void
1367
dd_context_resource_copy_region(struct pipe_context *_pipe,
1368
struct pipe_resource *dst, unsigned dst_level,
1369
unsigned dstx, unsigned dsty, unsigned dstz,
1370
struct pipe_resource *src, unsigned src_level,
1371
const struct pipe_box *src_box)
1372
{
1373
struct dd_context *dctx = dd_context(_pipe);
1374
struct pipe_context *pipe = dctx->pipe;
1375
struct dd_draw_record *record = dd_create_record(dctx);
1376
1377
record->call.type = CALL_RESOURCE_COPY_REGION;
1378
record->call.info.resource_copy_region.dst = NULL;
1379
pipe_resource_reference(&record->call.info.resource_copy_region.dst, dst);
1380
record->call.info.resource_copy_region.dst_level = dst_level;
1381
record->call.info.resource_copy_region.dstx = dstx;
1382
record->call.info.resource_copy_region.dsty = dsty;
1383
record->call.info.resource_copy_region.dstz = dstz;
1384
record->call.info.resource_copy_region.src = NULL;
1385
pipe_resource_reference(&record->call.info.resource_copy_region.src, src);
1386
record->call.info.resource_copy_region.src_level = src_level;
1387
record->call.info.resource_copy_region.src_box = *src_box;
1388
1389
dd_before_draw(dctx, record);
1390
pipe->resource_copy_region(pipe,
1391
dst, dst_level, dstx, dsty, dstz,
1392
src, src_level, src_box);
1393
dd_after_draw(dctx, record);
1394
}
1395
1396
static void
1397
dd_context_blit(struct pipe_context *_pipe, const struct pipe_blit_info *info)
1398
{
1399
struct dd_context *dctx = dd_context(_pipe);
1400
struct pipe_context *pipe = dctx->pipe;
1401
struct dd_draw_record *record = dd_create_record(dctx);
1402
1403
record->call.type = CALL_BLIT;
1404
record->call.info.blit = *info;
1405
record->call.info.blit.dst.resource = NULL;
1406
pipe_resource_reference(&record->call.info.blit.dst.resource, info->dst.resource);
1407
record->call.info.blit.src.resource = NULL;
1408
pipe_resource_reference(&record->call.info.blit.src.resource, info->src.resource);
1409
1410
dd_before_draw(dctx, record);
1411
pipe->blit(pipe, info);
1412
dd_after_draw(dctx, record);
1413
}
1414
1415
static bool
1416
dd_context_generate_mipmap(struct pipe_context *_pipe,
1417
struct pipe_resource *res,
1418
enum pipe_format format,
1419
unsigned base_level,
1420
unsigned last_level,
1421
unsigned first_layer,
1422
unsigned last_layer)
1423
{
1424
struct dd_context *dctx = dd_context(_pipe);
1425
struct pipe_context *pipe = dctx->pipe;
1426
struct dd_draw_record *record = dd_create_record(dctx);
1427
bool result;
1428
1429
record->call.type = CALL_GENERATE_MIPMAP;
1430
record->call.info.generate_mipmap.res = NULL;
1431
pipe_resource_reference(&record->call.info.generate_mipmap.res, res);
1432
record->call.info.generate_mipmap.format = format;
1433
record->call.info.generate_mipmap.base_level = base_level;
1434
record->call.info.generate_mipmap.last_level = last_level;
1435
record->call.info.generate_mipmap.first_layer = first_layer;
1436
record->call.info.generate_mipmap.last_layer = last_layer;
1437
1438
dd_before_draw(dctx, record);
1439
result = pipe->generate_mipmap(pipe, res, format, base_level, last_level,
1440
first_layer, last_layer);
1441
dd_after_draw(dctx, record);
1442
return result;
1443
}
1444
1445
static void
1446
dd_context_get_query_result_resource(struct pipe_context *_pipe,
1447
struct pipe_query *query,
1448
bool wait,
1449
enum pipe_query_value_type result_type,
1450
int index,
1451
struct pipe_resource *resource,
1452
unsigned offset)
1453
{
1454
struct dd_context *dctx = dd_context(_pipe);
1455
struct dd_query *dquery = dd_query(query);
1456
struct pipe_context *pipe = dctx->pipe;
1457
struct dd_draw_record *record = dd_create_record(dctx);
1458
1459
record->call.type = CALL_GET_QUERY_RESULT_RESOURCE;
1460
record->call.info.get_query_result_resource.query = query;
1461
record->call.info.get_query_result_resource.wait = wait;
1462
record->call.info.get_query_result_resource.result_type = result_type;
1463
record->call.info.get_query_result_resource.index = index;
1464
record->call.info.get_query_result_resource.resource = NULL;
1465
pipe_resource_reference(&record->call.info.get_query_result_resource.resource,
1466
resource);
1467
record->call.info.get_query_result_resource.offset = offset;
1468
1469
/* The query may be deleted by the time we need to print it. */
1470
record->call.info.get_query_result_resource.query_type = dquery->type;
1471
1472
dd_before_draw(dctx, record);
1473
pipe->get_query_result_resource(pipe, dquery->query, wait,
1474
result_type, index, resource, offset);
1475
dd_after_draw(dctx, record);
1476
}
1477
1478
static void
1479
dd_context_flush_resource(struct pipe_context *_pipe,
1480
struct pipe_resource *resource)
1481
{
1482
struct dd_context *dctx = dd_context(_pipe);
1483
struct pipe_context *pipe = dctx->pipe;
1484
struct dd_draw_record *record = dd_create_record(dctx);
1485
1486
record->call.type = CALL_FLUSH_RESOURCE;
1487
record->call.info.flush_resource = NULL;
1488
pipe_resource_reference(&record->call.info.flush_resource, resource);
1489
1490
dd_before_draw(dctx, record);
1491
pipe->flush_resource(pipe, resource);
1492
dd_after_draw(dctx, record);
1493
}
1494
1495
static void
1496
dd_context_clear(struct pipe_context *_pipe, unsigned buffers, const struct pipe_scissor_state *scissor_state,
1497
const union pipe_color_union *color, double depth,
1498
unsigned stencil)
1499
{
1500
struct dd_context *dctx = dd_context(_pipe);
1501
struct pipe_context *pipe = dctx->pipe;
1502
struct dd_draw_record *record = dd_create_record(dctx);
1503
1504
record->call.type = CALL_CLEAR;
1505
record->call.info.clear.buffers = buffers;
1506
if (scissor_state)
1507
record->call.info.clear.scissor_state = *scissor_state;
1508
record->call.info.clear.color = *color;
1509
record->call.info.clear.depth = depth;
1510
record->call.info.clear.stencil = stencil;
1511
1512
dd_before_draw(dctx, record);
1513
pipe->clear(pipe, buffers, scissor_state, color, depth, stencil);
1514
dd_after_draw(dctx, record);
1515
}
1516
1517
static void
1518
dd_context_clear_render_target(struct pipe_context *_pipe,
1519
struct pipe_surface *dst,
1520
const union pipe_color_union *color,
1521
unsigned dstx, unsigned dsty,
1522
unsigned width, unsigned height,
1523
bool render_condition_enabled)
1524
{
1525
struct dd_context *dctx = dd_context(_pipe);
1526
struct pipe_context *pipe = dctx->pipe;
1527
struct dd_draw_record *record = dd_create_record(dctx);
1528
1529
record->call.type = CALL_CLEAR_RENDER_TARGET;
1530
1531
dd_before_draw(dctx, record);
1532
pipe->clear_render_target(pipe, dst, color, dstx, dsty, width, height,
1533
render_condition_enabled);
1534
dd_after_draw(dctx, record);
1535
}
1536
1537
static void
1538
dd_context_clear_depth_stencil(struct pipe_context *_pipe,
1539
struct pipe_surface *dst, unsigned clear_flags,
1540
double depth, unsigned stencil, unsigned dstx,
1541
unsigned dsty, unsigned width, unsigned height,
1542
bool render_condition_enabled)
1543
{
1544
struct dd_context *dctx = dd_context(_pipe);
1545
struct pipe_context *pipe = dctx->pipe;
1546
struct dd_draw_record *record = dd_create_record(dctx);
1547
1548
record->call.type = CALL_CLEAR_DEPTH_STENCIL;
1549
1550
dd_before_draw(dctx, record);
1551
pipe->clear_depth_stencil(pipe, dst, clear_flags, depth, stencil,
1552
dstx, dsty, width, height,
1553
render_condition_enabled);
1554
dd_after_draw(dctx, record);
1555
}
1556
1557
static void
1558
dd_context_clear_buffer(struct pipe_context *_pipe, struct pipe_resource *res,
1559
unsigned offset, unsigned size,
1560
const void *clear_value, int clear_value_size)
1561
{
1562
struct dd_context *dctx = dd_context(_pipe);
1563
struct pipe_context *pipe = dctx->pipe;
1564
struct dd_draw_record *record = dd_create_record(dctx);
1565
1566
record->call.type = CALL_CLEAR_BUFFER;
1567
record->call.info.clear_buffer.res = NULL;
1568
pipe_resource_reference(&record->call.info.clear_buffer.res, res);
1569
record->call.info.clear_buffer.offset = offset;
1570
record->call.info.clear_buffer.size = size;
1571
record->call.info.clear_buffer.clear_value = clear_value;
1572
record->call.info.clear_buffer.clear_value_size = clear_value_size;
1573
1574
dd_before_draw(dctx, record);
1575
pipe->clear_buffer(pipe, res, offset, size, clear_value, clear_value_size);
1576
dd_after_draw(dctx, record);
1577
}
1578
1579
static void
1580
dd_context_clear_texture(struct pipe_context *_pipe,
1581
struct pipe_resource *res,
1582
unsigned level,
1583
const struct pipe_box *box,
1584
const void *data)
1585
{
1586
struct dd_context *dctx = dd_context(_pipe);
1587
struct pipe_context *pipe = dctx->pipe;
1588
struct dd_draw_record *record = dd_create_record(dctx);
1589
1590
record->call.type = CALL_CLEAR_TEXTURE;
1591
1592
dd_before_draw(dctx, record);
1593
pipe->clear_texture(pipe, res, level, box, data);
1594
dd_after_draw(dctx, record);
1595
}
1596
1597
/********************************************************************
1598
* transfer
1599
*/
1600
1601
static void *
1602
dd_context_buffer_map(struct pipe_context *_pipe,
1603
struct pipe_resource *resource, unsigned level,
1604
unsigned usage, const struct pipe_box *box,
1605
struct pipe_transfer **transfer)
1606
{
1607
struct dd_context *dctx = dd_context(_pipe);
1608
struct pipe_context *pipe = dctx->pipe;
1609
struct dd_draw_record *record =
1610
dd_screen(dctx->base.screen)->transfers ? dd_create_record(dctx) : NULL;
1611
1612
if (record) {
1613
record->call.type = CALL_TRANSFER_MAP;
1614
1615
dd_before_draw(dctx, record);
1616
}
1617
void *ptr = pipe->buffer_map(pipe, resource, level, usage, box, transfer);
1618
if (record) {
1619
record->call.info.transfer_map.transfer_ptr = *transfer;
1620
record->call.info.transfer_map.ptr = ptr;
1621
if (*transfer) {
1622
record->call.info.transfer_map.transfer = **transfer;
1623
record->call.info.transfer_map.transfer.resource = NULL;
1624
pipe_resource_reference(&record->call.info.transfer_map.transfer.resource,
1625
(*transfer)->resource);
1626
} else {
1627
memset(&record->call.info.transfer_map.transfer, 0, sizeof(struct pipe_transfer));
1628
}
1629
1630
dd_after_draw(dctx, record);
1631
}
1632
return ptr;
1633
}
1634
1635
static void *
1636
dd_context_texture_map(struct pipe_context *_pipe,
1637
struct pipe_resource *resource, unsigned level,
1638
unsigned usage, const struct pipe_box *box,
1639
struct pipe_transfer **transfer)
1640
{
1641
struct dd_context *dctx = dd_context(_pipe);
1642
struct pipe_context *pipe = dctx->pipe;
1643
struct dd_draw_record *record =
1644
dd_screen(dctx->base.screen)->transfers ? dd_create_record(dctx) : NULL;
1645
1646
if (record) {
1647
record->call.type = CALL_TRANSFER_MAP;
1648
1649
dd_before_draw(dctx, record);
1650
}
1651
void *ptr = pipe->texture_map(pipe, resource, level, usage, box, transfer);
1652
if (record) {
1653
record->call.info.transfer_map.transfer_ptr = *transfer;
1654
record->call.info.transfer_map.ptr = ptr;
1655
if (*transfer) {
1656
record->call.info.transfer_map.transfer = **transfer;
1657
record->call.info.transfer_map.transfer.resource = NULL;
1658
pipe_resource_reference(&record->call.info.transfer_map.transfer.resource,
1659
(*transfer)->resource);
1660
} else {
1661
memset(&record->call.info.transfer_map.transfer, 0, sizeof(struct pipe_transfer));
1662
}
1663
1664
dd_after_draw(dctx, record);
1665
}
1666
return ptr;
1667
}
1668
1669
static void
1670
dd_context_transfer_flush_region(struct pipe_context *_pipe,
1671
struct pipe_transfer *transfer,
1672
const struct pipe_box *box)
1673
{
1674
struct dd_context *dctx = dd_context(_pipe);
1675
struct pipe_context *pipe = dctx->pipe;
1676
struct dd_draw_record *record =
1677
dd_screen(dctx->base.screen)->transfers ? dd_create_record(dctx) : NULL;
1678
1679
if (record) {
1680
record->call.type = CALL_TRANSFER_FLUSH_REGION;
1681
record->call.info.transfer_flush_region.transfer_ptr = transfer;
1682
record->call.info.transfer_flush_region.box = *box;
1683
record->call.info.transfer_flush_region.transfer = *transfer;
1684
record->call.info.transfer_flush_region.transfer.resource = NULL;
1685
pipe_resource_reference(
1686
&record->call.info.transfer_flush_region.transfer.resource,
1687
transfer->resource);
1688
1689
dd_before_draw(dctx, record);
1690
}
1691
pipe->transfer_flush_region(pipe, transfer, box);
1692
if (record)
1693
dd_after_draw(dctx, record);
1694
}
1695
1696
static void
1697
dd_context_buffer_unmap(struct pipe_context *_pipe,
1698
struct pipe_transfer *transfer)
1699
{
1700
struct dd_context *dctx = dd_context(_pipe);
1701
struct pipe_context *pipe = dctx->pipe;
1702
struct dd_draw_record *record =
1703
dd_screen(dctx->base.screen)->transfers ? dd_create_record(dctx) : NULL;
1704
1705
if (record) {
1706
record->call.type = CALL_TRANSFER_UNMAP;
1707
record->call.info.transfer_unmap.transfer_ptr = transfer;
1708
record->call.info.transfer_unmap.transfer = *transfer;
1709
record->call.info.transfer_unmap.transfer.resource = NULL;
1710
pipe_resource_reference(
1711
&record->call.info.transfer_unmap.transfer.resource,
1712
transfer->resource);
1713
1714
dd_before_draw(dctx, record);
1715
}
1716
pipe->buffer_unmap(pipe, transfer);
1717
if (record)
1718
dd_after_draw(dctx, record);
1719
}
1720
1721
static void
1722
dd_context_texture_unmap(struct pipe_context *_pipe,
1723
struct pipe_transfer *transfer)
1724
{
1725
struct dd_context *dctx = dd_context(_pipe);
1726
struct pipe_context *pipe = dctx->pipe;
1727
struct dd_draw_record *record =
1728
dd_screen(dctx->base.screen)->transfers ? dd_create_record(dctx) : NULL;
1729
1730
if (record) {
1731
record->call.type = CALL_TRANSFER_UNMAP;
1732
record->call.info.transfer_unmap.transfer_ptr = transfer;
1733
record->call.info.transfer_unmap.transfer = *transfer;
1734
record->call.info.transfer_unmap.transfer.resource = NULL;
1735
pipe_resource_reference(
1736
&record->call.info.transfer_unmap.transfer.resource,
1737
transfer->resource);
1738
1739
dd_before_draw(dctx, record);
1740
}
1741
pipe->texture_unmap(pipe, transfer);
1742
if (record)
1743
dd_after_draw(dctx, record);
1744
}
1745
1746
static void
1747
dd_context_buffer_subdata(struct pipe_context *_pipe,
1748
struct pipe_resource *resource,
1749
unsigned usage, unsigned offset,
1750
unsigned size, const void *data)
1751
{
1752
struct dd_context *dctx = dd_context(_pipe);
1753
struct pipe_context *pipe = dctx->pipe;
1754
struct dd_draw_record *record =
1755
dd_screen(dctx->base.screen)->transfers ? dd_create_record(dctx) : NULL;
1756
1757
if (record) {
1758
record->call.type = CALL_BUFFER_SUBDATA;
1759
record->call.info.buffer_subdata.resource = NULL;
1760
pipe_resource_reference(&record->call.info.buffer_subdata.resource, resource);
1761
record->call.info.buffer_subdata.usage = usage;
1762
record->call.info.buffer_subdata.offset = offset;
1763
record->call.info.buffer_subdata.size = size;
1764
record->call.info.buffer_subdata.data = data;
1765
1766
dd_before_draw(dctx, record);
1767
}
1768
pipe->buffer_subdata(pipe, resource, usage, offset, size, data);
1769
if (record)
1770
dd_after_draw(dctx, record);
1771
}
1772
1773
static void
1774
dd_context_texture_subdata(struct pipe_context *_pipe,
1775
struct pipe_resource *resource,
1776
unsigned level, unsigned usage,
1777
const struct pipe_box *box,
1778
const void *data, unsigned stride,
1779
unsigned layer_stride)
1780
{
1781
struct dd_context *dctx = dd_context(_pipe);
1782
struct pipe_context *pipe = dctx->pipe;
1783
struct dd_draw_record *record =
1784
dd_screen(dctx->base.screen)->transfers ? dd_create_record(dctx) : NULL;
1785
1786
if (record) {
1787
record->call.type = CALL_TEXTURE_SUBDATA;
1788
record->call.info.texture_subdata.resource = NULL;
1789
pipe_resource_reference(&record->call.info.texture_subdata.resource, resource);
1790
record->call.info.texture_subdata.level = level;
1791
record->call.info.texture_subdata.usage = usage;
1792
record->call.info.texture_subdata.box = *box;
1793
record->call.info.texture_subdata.data = data;
1794
record->call.info.texture_subdata.stride = stride;
1795
record->call.info.texture_subdata.layer_stride = layer_stride;
1796
1797
dd_before_draw(dctx, record);
1798
}
1799
pipe->texture_subdata(pipe, resource, level, usage, box, data,
1800
stride, layer_stride);
1801
if (record)
1802
dd_after_draw(dctx, record);
1803
}
1804
1805
void
1806
dd_init_draw_functions(struct dd_context *dctx)
1807
{
1808
CTX_INIT(flush);
1809
CTX_INIT(draw_vbo);
1810
CTX_INIT(launch_grid);
1811
CTX_INIT(resource_copy_region);
1812
CTX_INIT(blit);
1813
CTX_INIT(clear);
1814
CTX_INIT(clear_render_target);
1815
CTX_INIT(clear_depth_stencil);
1816
CTX_INIT(clear_buffer);
1817
CTX_INIT(clear_texture);
1818
CTX_INIT(flush_resource);
1819
CTX_INIT(generate_mipmap);
1820
CTX_INIT(get_query_result_resource);
1821
CTX_INIT(buffer_map);
1822
CTX_INIT(texture_map);
1823
CTX_INIT(transfer_flush_region);
1824
CTX_INIT(buffer_unmap);
1825
CTX_INIT(texture_unmap);
1826
CTX_INIT(buffer_subdata);
1827
CTX_INIT(texture_subdata);
1828
}
1829
1830