Home | History | Annotate | Download | only in ddebug
      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 <stdio.h>
     32 
     33 
     34 static const char *
     35 dd_screen_get_name(struct pipe_screen *_screen)
     36 {
     37    struct pipe_screen *screen = dd_screen(_screen)->screen;
     38 
     39    return screen->get_name(screen);
     40 }
     41 
     42 static const char *
     43 dd_screen_get_vendor(struct pipe_screen *_screen)
     44 {
     45    struct pipe_screen *screen = dd_screen(_screen)->screen;
     46 
     47    return screen->get_vendor(screen);
     48 }
     49 
     50 static const char *
     51 dd_screen_get_device_vendor(struct pipe_screen *_screen)
     52 {
     53    struct pipe_screen *screen = dd_screen(_screen)->screen;
     54 
     55    return screen->get_device_vendor(screen);
     56 }
     57 
     58 static int
     59 dd_screen_get_param(struct pipe_screen *_screen,
     60                     enum pipe_cap param)
     61 {
     62    struct pipe_screen *screen = dd_screen(_screen)->screen;
     63 
     64    return screen->get_param(screen, param);
     65 }
     66 
     67 static float
     68 dd_screen_get_paramf(struct pipe_screen *_screen,
     69                      enum pipe_capf param)
     70 {
     71    struct pipe_screen *screen = dd_screen(_screen)->screen;
     72 
     73    return screen->get_paramf(screen, param);
     74 }
     75 
     76 static int
     77 dd_screen_get_compute_param(struct pipe_screen *_screen,
     78                             enum pipe_shader_ir ir_type,
     79                             enum pipe_compute_cap param,
     80                             void *ret)
     81 {
     82    struct pipe_screen *screen = dd_screen(_screen)->screen;
     83 
     84    return screen->get_compute_param(screen, ir_type, param, ret);
     85 }
     86 
     87 static int
     88 dd_screen_get_shader_param(struct pipe_screen *_screen, unsigned shader,
     89                            enum pipe_shader_cap param)
     90 {
     91    struct pipe_screen *screen = dd_screen(_screen)->screen;
     92 
     93    return screen->get_shader_param(screen, shader, param);
     94 }
     95 
     96 static uint64_t
     97 dd_screen_get_timestamp(struct pipe_screen *_screen)
     98 {
     99    struct pipe_screen *screen = dd_screen(_screen)->screen;
    100 
    101    return screen->get_timestamp(screen);
    102 }
    103 
    104 static void dd_screen_query_memory_info(struct pipe_screen *_screen,
    105                                         struct pipe_memory_info *info)
    106 {
    107    struct pipe_screen *screen = dd_screen(_screen)->screen;
    108 
    109    return screen->query_memory_info(screen, info);
    110 }
    111 
    112 static struct pipe_context *
    113 dd_screen_context_create(struct pipe_screen *_screen, void *priv,
    114                          unsigned flags)
    115 {
    116    struct dd_screen *dscreen = dd_screen(_screen);
    117    struct pipe_screen *screen = dscreen->screen;
    118 
    119    flags |= PIPE_CONTEXT_DEBUG;
    120 
    121    return dd_context_create(dscreen,
    122                             screen->context_create(screen, priv, flags));
    123 }
    124 
    125 static boolean
    126 dd_screen_is_format_supported(struct pipe_screen *_screen,
    127                               enum pipe_format format,
    128                               enum pipe_texture_target target,
    129                               unsigned sample_count,
    130                               unsigned tex_usage)
    131 {
    132    struct pipe_screen *screen = dd_screen(_screen)->screen;
    133 
    134    return screen->is_format_supported(screen, format, target, sample_count,
    135                                       tex_usage);
    136 }
    137 
    138 static boolean
    139 dd_screen_can_create_resource(struct pipe_screen *_screen,
    140                               const struct pipe_resource *templat)
    141 {
    142    struct pipe_screen *screen = dd_screen(_screen)->screen;
    143 
    144    return screen->can_create_resource(screen, templat);
    145 }
    146 
    147 static void
    148 dd_screen_flush_frontbuffer(struct pipe_screen *_screen,
    149                             struct pipe_resource *resource,
    150                             unsigned level, unsigned layer,
    151                             void *context_private,
    152                             struct pipe_box *sub_box)
    153 {
    154    struct pipe_screen *screen = dd_screen(_screen)->screen;
    155 
    156    screen->flush_frontbuffer(screen, resource, level, layer, context_private,
    157                              sub_box);
    158 }
    159 
    160 static int
    161 dd_screen_get_driver_query_info(struct pipe_screen *_screen,
    162                                 unsigned index,
    163                                 struct pipe_driver_query_info *info)
    164 {
    165    struct pipe_screen *screen = dd_screen(_screen)->screen;
    166 
    167    return screen->get_driver_query_info(screen, index, info);
    168 }
    169 
    170 static int
    171 dd_screen_get_driver_query_group_info(struct pipe_screen *_screen,
    172                                       unsigned index,
    173                                       struct pipe_driver_query_group_info *info)
    174 {
    175    struct pipe_screen *screen = dd_screen(_screen)->screen;
    176 
    177    return screen->get_driver_query_group_info(screen, index, info);
    178 }
    179 
    180 
    181 /********************************************************************
    182  * resource
    183  */
    184 
    185 static struct pipe_resource *
    186 dd_screen_resource_create(struct pipe_screen *_screen,
    187                           const struct pipe_resource *templat)
    188 {
    189    struct pipe_screen *screen = dd_screen(_screen)->screen;
    190    struct pipe_resource *res = screen->resource_create(screen, templat);
    191 
    192    if (!res)
    193       return NULL;
    194    res->screen = _screen;
    195    return res;
    196 }
    197 
    198 static struct pipe_resource *
    199 dd_screen_resource_from_handle(struct pipe_screen *_screen,
    200                                const struct pipe_resource *templ,
    201                                struct winsys_handle *handle,
    202                                unsigned usage)
    203 {
    204    struct pipe_screen *screen = dd_screen(_screen)->screen;
    205    struct pipe_resource *res =
    206       screen->resource_from_handle(screen, templ, handle, usage);
    207 
    208    if (!res)
    209       return NULL;
    210    res->screen = _screen;
    211    return res;
    212 }
    213 
    214 static struct pipe_resource *
    215 dd_screen_resource_from_user_memory(struct pipe_screen *_screen,
    216                                     const struct pipe_resource *templ,
    217                                     void *user_memory)
    218 {
    219    struct pipe_screen *screen = dd_screen(_screen)->screen;
    220    struct pipe_resource *res =
    221       screen->resource_from_user_memory(screen, templ, user_memory);
    222 
    223    if (!res)
    224       return NULL;
    225    res->screen = _screen;
    226    return res;
    227 }
    228 
    229 static void
    230 dd_screen_resource_destroy(struct pipe_screen *_screen,
    231                            struct pipe_resource *res)
    232 {
    233    struct pipe_screen *screen = dd_screen(_screen)->screen;
    234 
    235    screen->resource_destroy(screen, res);
    236 }
    237 
    238 static boolean
    239 dd_screen_resource_get_handle(struct pipe_screen *_screen,
    240                               struct pipe_context *_pipe,
    241                               struct pipe_resource *resource,
    242                               struct winsys_handle *handle,
    243                               unsigned usage)
    244 {
    245    struct pipe_screen *screen = dd_screen(_screen)->screen;
    246    struct pipe_context *pipe = _pipe ? dd_context(_pipe)->pipe : NULL;
    247 
    248    return screen->resource_get_handle(screen, pipe, resource, handle, usage);
    249 }
    250 
    251 
    252 /********************************************************************
    253  * fence
    254  */
    255 
    256 static void
    257 dd_screen_fence_reference(struct pipe_screen *_screen,
    258                           struct pipe_fence_handle **pdst,
    259                           struct pipe_fence_handle *src)
    260 {
    261    struct pipe_screen *screen = dd_screen(_screen)->screen;
    262 
    263    screen->fence_reference(screen, pdst, src);
    264 }
    265 
    266 static boolean
    267 dd_screen_fence_finish(struct pipe_screen *_screen,
    268                        struct pipe_context *_ctx,
    269                        struct pipe_fence_handle *fence,
    270                        uint64_t timeout)
    271 {
    272    struct pipe_screen *screen = dd_screen(_screen)->screen;
    273    struct pipe_context *ctx = _ctx ? dd_context(_ctx)->pipe : NULL;
    274 
    275    return screen->fence_finish(screen, ctx, fence, timeout);
    276 }
    277 
    278 
    279 /********************************************************************
    280  * screen
    281  */
    282 
    283 static void
    284 dd_screen_destroy(struct pipe_screen *_screen)
    285 {
    286    struct dd_screen *dscreen = dd_screen(_screen);
    287    struct pipe_screen *screen = dscreen->screen;
    288 
    289    screen->destroy(screen);
    290    FREE(dscreen);
    291 }
    292 
    293 struct pipe_screen *
    294 ddebug_screen_create(struct pipe_screen *screen)
    295 {
    296    struct dd_screen *dscreen;
    297    const char *option;
    298    bool no_flush;
    299    unsigned timeout = 0;
    300    unsigned apitrace_dump_call = 0;
    301    enum dd_mode mode;
    302 
    303    option = debug_get_option("GALLIUM_DDEBUG", NULL);
    304    if (!option)
    305       return screen;
    306 
    307    if (!strcmp(option, "help")) {
    308       puts("Gallium driver debugger");
    309       puts("");
    310       puts("Usage:");
    311       puts("");
    312       puts("  GALLIUM_DDEBUG=\"always [noflush] [verbose]\"");
    313       puts("    Flush and dump context and driver information after every draw call into");
    314       puts("    $HOME/"DD_DIR"/.");
    315       puts("");
    316       puts("  GALLIUM_DDEBUG=\"[timeout in ms] [noflush] [verbose]\"");
    317       puts("    Flush and detect a device hang after every draw call based on the given");
    318       puts("    fence timeout and dump context and driver information into");
    319       puts("    $HOME/"DD_DIR"/ when a hang is detected.");
    320       puts("");
    321       puts("  GALLIUM_DDEBUG=\"pipelined [timeout in ms] [verbose]\"");
    322       puts("    Detect a device hang after every draw call based on the given fence");
    323       puts("    timeout without flushes and dump context and driver information into");
    324       puts("    $HOME/"DD_DIR"/ when a hang is detected.");
    325       puts("");
    326       puts("  GALLIUM_DDEBUG=\"apitrace [call#] [verbose]\"");
    327       puts("    Dump apitrace draw call information into $HOME/"DD_DIR"/. Implies 'noflush'.");
    328       puts("");
    329       puts("  If 'noflush' is specified, do not flush on every draw call. In hang");
    330       puts("  detection mode, this only detect hangs in pipe->flush.");
    331       puts("  If 'verbose' is specified, additional information is written to stderr.");
    332       puts("");
    333       puts("  GALLIUM_DDEBUG_SKIP=[count]");
    334       puts("    Skip flush and hang detection for the given initial number of draw calls.");
    335       puts("");
    336       exit(0);
    337    }
    338 
    339    no_flush = strstr(option, "noflush") != NULL;
    340 
    341    if (!strncmp(option, "always", 6)) {
    342       mode = DD_DUMP_ALL_CALLS;
    343    } else if (!strncmp(option, "apitrace", 8)) {
    344       mode = DD_DUMP_APITRACE_CALL;
    345       no_flush = true;
    346 
    347       if (sscanf(option+8, "%u", &apitrace_dump_call) != 1)
    348          return screen;
    349    } else if (!strncmp(option, "pipelined", 8)) {
    350       mode = DD_DETECT_HANGS_PIPELINED;
    351 
    352       if (sscanf(option+10, "%u", &timeout) != 1)
    353          return screen;
    354    } else {
    355       mode = DD_DETECT_HANGS;
    356 
    357       if (sscanf(option, "%u", &timeout) != 1)
    358          return screen;
    359    }
    360 
    361    dscreen = CALLOC_STRUCT(dd_screen);
    362    if (!dscreen)
    363       return NULL;
    364 
    365 #define SCR_INIT(_member) \
    366    dscreen->base._member = screen->_member ? dd_screen_##_member : NULL
    367 
    368    dscreen->base.destroy = dd_screen_destroy;
    369    dscreen->base.get_name = dd_screen_get_name;
    370    dscreen->base.get_vendor = dd_screen_get_vendor;
    371    dscreen->base.get_device_vendor = dd_screen_get_device_vendor;
    372    dscreen->base.get_param = dd_screen_get_param;
    373    dscreen->base.get_paramf = dd_screen_get_paramf;
    374    dscreen->base.get_compute_param = dd_screen_get_compute_param;
    375    dscreen->base.get_shader_param = dd_screen_get_shader_param;
    376    dscreen->base.query_memory_info = dd_screen_query_memory_info;
    377    /* get_video_param */
    378    /* get_compute_param */
    379    SCR_INIT(get_timestamp);
    380    dscreen->base.context_create = dd_screen_context_create;
    381    dscreen->base.is_format_supported = dd_screen_is_format_supported;
    382    /* is_video_format_supported */
    383    SCR_INIT(can_create_resource);
    384    dscreen->base.resource_create = dd_screen_resource_create;
    385    dscreen->base.resource_from_handle = dd_screen_resource_from_handle;
    386    SCR_INIT(resource_from_user_memory);
    387    dscreen->base.resource_get_handle = dd_screen_resource_get_handle;
    388    dscreen->base.resource_destroy = dd_screen_resource_destroy;
    389    SCR_INIT(flush_frontbuffer);
    390    SCR_INIT(fence_reference);
    391    SCR_INIT(fence_finish);
    392    SCR_INIT(get_driver_query_info);
    393    SCR_INIT(get_driver_query_group_info);
    394 
    395 #undef SCR_INIT
    396 
    397    dscreen->screen = screen;
    398    dscreen->timeout_ms = timeout;
    399    dscreen->mode = mode;
    400    dscreen->no_flush = no_flush;
    401    dscreen->verbose = strstr(option, "verbose") != NULL;
    402    dscreen->apitrace_dump_call = apitrace_dump_call;
    403 
    404    switch (dscreen->mode) {
    405    case DD_DUMP_ALL_CALLS:
    406       fprintf(stderr, "Gallium debugger active. Logging all calls.\n");
    407       break;
    408    case DD_DETECT_HANGS:
    409    case DD_DETECT_HANGS_PIPELINED:
    410       fprintf(stderr, "Gallium debugger active. "
    411               "The hang detection timeout is %i ms.\n", timeout);
    412       break;
    413    case DD_DUMP_APITRACE_CALL:
    414       fprintf(stderr, "Gallium debugger active. Going to dump an apitrace call.\n");
    415       break;
    416    default:
    417       assert(0);
    418    }
    419 
    420    dscreen->skip_count = debug_get_num_option("GALLIUM_DDEBUG_SKIP", 0);
    421    if (dscreen->skip_count > 0) {
    422       fprintf(stderr, "Gallium debugger skipping the first %u draw calls.\n",
    423               dscreen->skip_count);
    424    }
    425 
    426    return &dscreen->base;
    427 }
    428