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#include "dd_public.h"
30#include "util/u_memory.h"
31#include <ctype.h>
32#include <stdio.h>
33
34
35static const char *
36dd_screen_get_name(struct pipe_screen *_screen)
37{
38   struct pipe_screen *screen = dd_screen(_screen)->screen;
39
40   return screen->get_name(screen);
41}
42
43static const char *
44dd_screen_get_vendor(struct pipe_screen *_screen)
45{
46   struct pipe_screen *screen = dd_screen(_screen)->screen;
47
48   return screen->get_vendor(screen);
49}
50
51static const char *
52dd_screen_get_device_vendor(struct pipe_screen *_screen)
53{
54   struct pipe_screen *screen = dd_screen(_screen)->screen;
55
56   return screen->get_device_vendor(screen);
57}
58
59static const void *
60dd_screen_get_compiler_options(struct pipe_screen *_screen,
61                               enum pipe_shader_ir ir,
62                               enum pipe_shader_type shader)
63{
64   struct pipe_screen *screen = dd_screen(_screen)->screen;
65
66   return screen->get_compiler_options(screen, ir, shader);
67}
68
69static struct disk_cache *
70dd_screen_get_disk_shader_cache(struct pipe_screen *_screen)
71{
72   struct pipe_screen *screen = dd_screen(_screen)->screen;
73
74   return screen->get_disk_shader_cache(screen);
75}
76
77static int
78dd_screen_get_param(struct pipe_screen *_screen,
79                    enum pipe_cap param)
80{
81   struct pipe_screen *screen = dd_screen(_screen)->screen;
82
83   return screen->get_param(screen, param);
84}
85
86static float
87dd_screen_get_paramf(struct pipe_screen *_screen,
88                     enum pipe_capf param)
89{
90   struct pipe_screen *screen = dd_screen(_screen)->screen;
91
92   return screen->get_paramf(screen, param);
93}
94
95static int
96dd_screen_get_compute_param(struct pipe_screen *_screen,
97                            enum pipe_shader_ir ir_type,
98                            enum pipe_compute_cap param,
99                            void *ret)
100{
101   struct pipe_screen *screen = dd_screen(_screen)->screen;
102
103   return screen->get_compute_param(screen, ir_type, param, ret);
104}
105
106static int
107dd_screen_get_shader_param(struct pipe_screen *_screen,
108                           enum pipe_shader_type shader,
109                           enum pipe_shader_cap param)
110{
111   struct pipe_screen *screen = dd_screen(_screen)->screen;
112
113   return screen->get_shader_param(screen, shader, param);
114}
115
116static uint64_t
117dd_screen_get_timestamp(struct pipe_screen *_screen)
118{
119   struct pipe_screen *screen = dd_screen(_screen)->screen;
120
121   return screen->get_timestamp(screen);
122}
123
124static void dd_screen_query_memory_info(struct pipe_screen *_screen,
125                                        struct pipe_memory_info *info)
126{
127   struct pipe_screen *screen = dd_screen(_screen)->screen;
128
129   return screen->query_memory_info(screen, info);
130}
131
132static struct pipe_context *
133dd_screen_context_create(struct pipe_screen *_screen, void *priv,
134                         unsigned flags)
135{
136   struct dd_screen *dscreen = dd_screen(_screen);
137   struct pipe_screen *screen = dscreen->screen;
138
139   flags |= PIPE_CONTEXT_DEBUG;
140
141   return dd_context_create(dscreen,
142                            screen->context_create(screen, priv, flags));
143}
144
145static boolean
146dd_screen_is_format_supported(struct pipe_screen *_screen,
147                              enum pipe_format format,
148                              enum pipe_texture_target target,
149                              unsigned sample_count,
150                              unsigned storage_sample_count,
151                              unsigned tex_usage)
152{
153   struct pipe_screen *screen = dd_screen(_screen)->screen;
154
155   return screen->is_format_supported(screen, format, target, sample_count,
156                                      storage_sample_count, tex_usage);
157}
158
159static boolean
160dd_screen_can_create_resource(struct pipe_screen *_screen,
161                              const struct pipe_resource *templat)
162{
163   struct pipe_screen *screen = dd_screen(_screen)->screen;
164
165   return screen->can_create_resource(screen, templat);
166}
167
168static void
169dd_screen_flush_frontbuffer(struct pipe_screen *_screen,
170                            struct pipe_resource *resource,
171                            unsigned level, unsigned layer,
172                            void *context_private,
173                            struct pipe_box *sub_box)
174{
175   struct pipe_screen *screen = dd_screen(_screen)->screen;
176
177   screen->flush_frontbuffer(screen, resource, level, layer, context_private,
178                             sub_box);
179}
180
181static int
182dd_screen_get_driver_query_info(struct pipe_screen *_screen,
183                                unsigned index,
184                                struct pipe_driver_query_info *info)
185{
186   struct pipe_screen *screen = dd_screen(_screen)->screen;
187
188   return screen->get_driver_query_info(screen, index, info);
189}
190
191static int
192dd_screen_get_driver_query_group_info(struct pipe_screen *_screen,
193                                      unsigned index,
194                                      struct pipe_driver_query_group_info *info)
195{
196   struct pipe_screen *screen = dd_screen(_screen)->screen;
197
198   return screen->get_driver_query_group_info(screen, index, info);
199}
200
201
202static void
203dd_screen_get_driver_uuid(struct pipe_screen *_screen, char *uuid)
204{
205   struct pipe_screen *screen = dd_screen(_screen)->screen;
206
207   screen->get_driver_uuid(screen, uuid);
208}
209
210static void
211dd_screen_get_device_uuid(struct pipe_screen *_screen, char *uuid)
212{
213   struct pipe_screen *screen = dd_screen(_screen)->screen;
214
215   screen->get_device_uuid(screen, uuid);
216}
217
218/********************************************************************
219 * resource
220 */
221
222static struct pipe_resource *
223dd_screen_resource_create(struct pipe_screen *_screen,
224                          const struct pipe_resource *templat)
225{
226   struct pipe_screen *screen = dd_screen(_screen)->screen;
227   struct pipe_resource *res = screen->resource_create(screen, templat);
228
229   if (!res)
230      return NULL;
231   res->screen = _screen;
232   return res;
233}
234
235static struct pipe_resource *
236dd_screen_resource_from_handle(struct pipe_screen *_screen,
237                               const struct pipe_resource *templ,
238                               struct winsys_handle *handle,
239                               unsigned usage)
240{
241   struct pipe_screen *screen = dd_screen(_screen)->screen;
242   struct pipe_resource *res =
243      screen->resource_from_handle(screen, templ, handle, usage);
244
245   if (!res)
246      return NULL;
247   res->screen = _screen;
248   return res;
249}
250
251static struct pipe_resource *
252dd_screen_resource_from_user_memory(struct pipe_screen *_screen,
253                                    const struct pipe_resource *templ,
254                                    void *user_memory)
255{
256   struct pipe_screen *screen = dd_screen(_screen)->screen;
257   struct pipe_resource *res =
258      screen->resource_from_user_memory(screen, templ, user_memory);
259
260   if (!res)
261      return NULL;
262   res->screen = _screen;
263   return res;
264}
265
266static struct pipe_resource *
267dd_screen_resource_from_memobj(struct pipe_screen *_screen,
268                               const struct pipe_resource *templ,
269                               struct pipe_memory_object *memobj,
270                               uint64_t offset)
271{
272   struct pipe_screen *screen = dd_screen(_screen)->screen;
273   struct pipe_resource *res =
274      screen->resource_from_memobj(screen, templ, memobj, offset);
275
276   if (!res)
277      return NULL;
278   res->screen = _screen;
279   return res;
280}
281
282static void
283dd_screen_resource_changed(struct pipe_screen *_screen,
284                           struct pipe_resource *res)
285{
286   struct pipe_screen *screen = dd_screen(_screen)->screen;
287
288   if (screen->resource_changed)
289      screen->resource_changed(screen, res);
290}
291
292static void
293dd_screen_resource_destroy(struct pipe_screen *_screen,
294                           struct pipe_resource *res)
295{
296   struct pipe_screen *screen = dd_screen(_screen)->screen;
297
298   screen->resource_destroy(screen, res);
299}
300
301static boolean
302dd_screen_resource_get_handle(struct pipe_screen *_screen,
303                              struct pipe_context *_pipe,
304                              struct pipe_resource *resource,
305                              struct winsys_handle *handle,
306                              unsigned usage)
307{
308   struct pipe_screen *screen = dd_screen(_screen)->screen;
309   struct pipe_context *pipe = _pipe ? dd_context(_pipe)->pipe : NULL;
310
311   return screen->resource_get_handle(screen, pipe, resource, handle, usage);
312}
313
314static void
315dd_screen_resource_get_info(struct pipe_screen *_screen,
316                            struct pipe_resource *resource,
317                            unsigned *stride,
318                            unsigned *offset)
319{
320   struct pipe_screen *screen = dd_screen(_screen)->screen;
321
322   screen->resource_get_info(screen, resource, stride, offset);
323}
324
325static bool
326dd_screen_check_resource_capability(struct pipe_screen *_screen,
327                                    struct pipe_resource *resource,
328                                    unsigned bind)
329{
330   struct pipe_screen *screen = dd_screen(_screen)->screen;
331
332   return screen->check_resource_capability(screen, resource, bind);
333}
334
335
336/********************************************************************
337 * fence
338 */
339
340static void
341dd_screen_fence_reference(struct pipe_screen *_screen,
342                          struct pipe_fence_handle **pdst,
343                          struct pipe_fence_handle *src)
344{
345   struct pipe_screen *screen = dd_screen(_screen)->screen;
346
347   screen->fence_reference(screen, pdst, src);
348}
349
350static boolean
351dd_screen_fence_finish(struct pipe_screen *_screen,
352                       struct pipe_context *_ctx,
353                       struct pipe_fence_handle *fence,
354                       uint64_t timeout)
355{
356   struct pipe_screen *screen = dd_screen(_screen)->screen;
357   struct pipe_context *ctx = _ctx ? dd_context(_ctx)->pipe : NULL;
358
359   return screen->fence_finish(screen, ctx, fence, timeout);
360}
361
362static int
363dd_screen_fence_get_fd(struct pipe_screen *_screen,
364                       struct pipe_fence_handle *fence)
365{
366   struct pipe_screen *screen = dd_screen(_screen)->screen;
367
368   return screen->fence_get_fd(screen, fence);
369}
370
371/********************************************************************
372 * memobj
373 */
374
375static struct pipe_memory_object *
376dd_screen_memobj_create_from_handle(struct pipe_screen *_screen,
377                                    struct winsys_handle *handle,
378                                    bool dedicated)
379{
380   struct pipe_screen *screen = dd_screen(_screen)->screen;
381
382   return screen->memobj_create_from_handle(screen, handle, dedicated);
383}
384
385static void
386dd_screen_memobj_destroy(struct pipe_screen *_screen,
387                         struct pipe_memory_object *memobj)
388{
389   struct pipe_screen *screen = dd_screen(_screen)->screen;
390
391   screen->memobj_destroy(screen, memobj);
392}
393/********************************************************************
394 * screen
395 */
396
397static void
398dd_screen_destroy(struct pipe_screen *_screen)
399{
400   struct dd_screen *dscreen = dd_screen(_screen);
401   struct pipe_screen *screen = dscreen->screen;
402
403   screen->destroy(screen);
404   FREE(dscreen);
405}
406
407static void
408skip_space(const char **p)
409{
410   while (isspace(**p))
411      (*p)++;
412}
413
414static bool
415match_word(const char **cur, const char *word)
416{
417   size_t len = strlen(word);
418   if (strncmp(*cur, word, len) != 0)
419      return false;
420
421   const char *p = *cur + len;
422   if (*p) {
423      if (!isspace(*p))
424         return false;
425
426      *cur = p + 1;
427   } else {
428      *cur = p;
429   }
430
431   return true;
432}
433
434static bool
435match_uint(const char **cur, unsigned *value)
436{
437   char *end;
438   unsigned v = strtoul(*cur, &end, 0);
439   if (end == *cur || (*end && !isspace(*end)))
440      return false;
441   *cur = end;
442   *value = v;
443   return true;
444}
445
446struct pipe_screen *
447ddebug_screen_create(struct pipe_screen *screen)
448{
449   struct dd_screen *dscreen;
450   const char *option;
451   bool flush = false;
452   bool verbose = false;
453   bool transfers = false;
454   unsigned timeout = 1000;
455   unsigned apitrace_dump_call = 0;
456   enum dd_dump_mode mode = DD_DUMP_ONLY_HANGS;
457
458   option = debug_get_option("GALLIUM_DDEBUG", NULL);
459   if (!option)
460      return screen;
461
462   if (!strcmp(option, "help")) {
463      puts("Gallium driver debugger");
464      puts("");
465      puts("Usage:");
466      puts("");
467      puts("  GALLIUM_DDEBUG=\"[<timeout in ms>] [(always|apitrace <call#)] [flush] [transfers] [verbose]\"");
468      puts("  GALLIUM_DDEBUG_SKIP=[count]");
469      puts("");
470      puts("Dump context and driver information of draw calls into");
471      puts("$HOME/"DD_DIR"/. By default, watch for GPU hangs and only dump information");
472      puts("about draw calls related to the hang.");
473      puts("");
474      puts("<timeout in ms>");
475      puts("  Change the default timeout for GPU hang detection (default=1000ms).");
476      puts("  Setting this to 0 will disable GPU hang detection entirely.");
477      puts("");
478      puts("always");
479      puts("  Dump information about all draw calls.");
480      puts("");
481      puts("transfers");
482      puts("  Also dump and do hang detection on transfers.");
483      puts("");
484      puts("apitrace <call#>");
485      puts("  Dump information about the draw call corresponding to the given");
486      puts("  apitrace call number and exit.");
487      puts("");
488      puts("flush");
489      puts("  Flush after every draw call.");
490      puts("");
491      puts("verbose");
492      puts("  Write additional information to stderr.");
493      puts("");
494      puts("GALLIUM_DDEBUG_SKIP=count");
495      puts("  Skip dumping on the first count draw calls (only relevant with 'always').");
496      puts("");
497      exit(0);
498   }
499
500   for (;;) {
501      skip_space(&option);
502      if (!*option)
503         break;
504
505      if (match_word(&option, "always")) {
506         if (mode == DD_DUMP_APITRACE_CALL) {
507            printf("ddebug: both 'always' and 'apitrace' specified\n");
508            exit(1);
509         }
510
511         mode = DD_DUMP_ALL_CALLS;
512      } else if (match_word(&option, "flush")) {
513         flush = true;
514      } else if (match_word(&option, "transfers")) {
515         transfers = true;
516      } else if (match_word(&option, "verbose")) {
517         verbose = true;
518      } else if (match_word(&option, "apitrace")) {
519         if (mode != DD_DUMP_ONLY_HANGS) {
520            printf("ddebug: 'apitrace' can only appear once and not mixed with 'always'\n");
521            exit(1);
522         }
523
524         if (!match_uint(&option, &apitrace_dump_call)) {
525            printf("ddebug: expected call number after 'apitrace'\n");
526            exit(1);
527         }
528
529         mode = DD_DUMP_APITRACE_CALL;
530      } else if (match_uint(&option, &timeout)) {
531         /* no-op */
532      } else {
533         printf("ddebug: bad options: %s\n", option);
534         exit(1);
535      }
536   }
537
538   dscreen = CALLOC_STRUCT(dd_screen);
539   if (!dscreen)
540      return NULL;
541
542#define SCR_INIT(_member) \
543   dscreen->base._member = screen->_member ? dd_screen_##_member : NULL
544
545   dscreen->base.destroy = dd_screen_destroy;
546   dscreen->base.get_name = dd_screen_get_name;
547   dscreen->base.get_vendor = dd_screen_get_vendor;
548   dscreen->base.get_device_vendor = dd_screen_get_device_vendor;
549   SCR_INIT(get_disk_shader_cache);
550   dscreen->base.get_param = dd_screen_get_param;
551   dscreen->base.get_paramf = dd_screen_get_paramf;
552   dscreen->base.get_compute_param = dd_screen_get_compute_param;
553   dscreen->base.get_shader_param = dd_screen_get_shader_param;
554   dscreen->base.query_memory_info = dd_screen_query_memory_info;
555   /* get_video_param */
556   /* get_compute_param */
557   SCR_INIT(get_timestamp);
558   dscreen->base.context_create = dd_screen_context_create;
559   dscreen->base.is_format_supported = dd_screen_is_format_supported;
560   /* is_video_format_supported */
561   SCR_INIT(can_create_resource);
562   dscreen->base.resource_create = dd_screen_resource_create;
563   dscreen->base.resource_from_handle = dd_screen_resource_from_handle;
564   SCR_INIT(resource_from_memobj);
565   SCR_INIT(resource_from_user_memory);
566   SCR_INIT(check_resource_capability);
567   dscreen->base.resource_get_handle = dd_screen_resource_get_handle;
568   SCR_INIT(resource_get_info);
569   SCR_INIT(resource_changed);
570   dscreen->base.resource_destroy = dd_screen_resource_destroy;
571   SCR_INIT(flush_frontbuffer);
572   SCR_INIT(fence_reference);
573   SCR_INIT(fence_finish);
574   SCR_INIT(fence_get_fd);
575   SCR_INIT(memobj_create_from_handle);
576   SCR_INIT(memobj_destroy);
577   SCR_INIT(get_driver_query_info);
578   SCR_INIT(get_driver_query_group_info);
579   SCR_INIT(get_compiler_options);
580   SCR_INIT(get_driver_uuid);
581   SCR_INIT(get_device_uuid);
582
583#undef SCR_INIT
584
585   dscreen->screen = screen;
586   dscreen->timeout_ms = timeout;
587   dscreen->dump_mode = mode;
588   dscreen->flush_always = flush;
589   dscreen->transfers = transfers;
590   dscreen->verbose = verbose;
591   dscreen->apitrace_dump_call = apitrace_dump_call;
592
593   switch (dscreen->dump_mode) {
594   case DD_DUMP_ALL_CALLS:
595      fprintf(stderr, "Gallium debugger active. Logging all calls.\n");
596      break;
597   case DD_DUMP_APITRACE_CALL:
598      fprintf(stderr, "Gallium debugger active. Going to dump an apitrace call.\n");
599      break;
600   default:
601      fprintf(stderr, "Gallium debugger active.\n");
602      break;
603   }
604
605   if (dscreen->timeout_ms > 0)
606      fprintf(stderr, "Hang detection timeout is %ums.\n", dscreen->timeout_ms);
607   else
608      fprintf(stderr, "Hang detection is disabled.\n");
609
610   dscreen->skip_count = debug_get_num_option("GALLIUM_DDEBUG_SKIP", 0);
611   if (dscreen->skip_count > 0) {
612      fprintf(stderr, "Gallium debugger skipping the first %u draw calls.\n",
613              dscreen->skip_count);
614   }
615
616   return &dscreen->base;
617}
618