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 *
dd_screen_get_name(struct pipe_screen * _screen)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 *
dd_screen_get_vendor(struct pipe_screen * _screen)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 *
dd_screen_get_device_vendor(struct pipe_screen * _screen)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
dd_screen_get_param(struct pipe_screen * _screen,enum pipe_cap param)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
dd_screen_get_paramf(struct pipe_screen * _screen,enum pipe_capf param)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
dd_screen_get_compute_param(struct pipe_screen * _screen,enum pipe_shader_ir ir_type,enum pipe_compute_cap param,void * ret)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
dd_screen_get_shader_param(struct pipe_screen * _screen,unsigned shader,enum pipe_shader_cap param)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
dd_screen_get_timestamp(struct pipe_screen * _screen)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 
dd_screen_query_memory_info(struct pipe_screen * _screen,struct pipe_memory_info * info)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 *
dd_screen_context_create(struct pipe_screen * _screen,void * priv,unsigned flags)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
dd_screen_is_format_supported(struct pipe_screen * _screen,enum pipe_format format,enum pipe_texture_target target,unsigned sample_count,unsigned tex_usage)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
dd_screen_can_create_resource(struct pipe_screen * _screen,const struct pipe_resource * templat)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
dd_screen_flush_frontbuffer(struct pipe_screen * _screen,struct pipe_resource * resource,unsigned level,unsigned layer,void * context_private,struct pipe_box * sub_box)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
dd_screen_get_driver_query_info(struct pipe_screen * _screen,unsigned index,struct pipe_driver_query_info * info)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
dd_screen_get_driver_query_group_info(struct pipe_screen * _screen,unsigned index,struct pipe_driver_query_group_info * info)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 *
dd_screen_resource_create(struct pipe_screen * _screen,const struct pipe_resource * templat)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 *
dd_screen_resource_from_handle(struct pipe_screen * _screen,const struct pipe_resource * templ,struct winsys_handle * handle,unsigned usage)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 *
dd_screen_resource_from_user_memory(struct pipe_screen * _screen,const struct pipe_resource * templ,void * user_memory)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
dd_screen_resource_destroy(struct pipe_screen * _screen,struct pipe_resource * res)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
dd_screen_resource_get_handle(struct pipe_screen * _screen,struct pipe_context * _pipe,struct pipe_resource * resource,struct winsys_handle * handle,unsigned usage)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
dd_screen_fence_reference(struct pipe_screen * _screen,struct pipe_fence_handle ** pdst,struct pipe_fence_handle * src)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
dd_screen_fence_finish(struct pipe_screen * _screen,struct pipe_context * _ctx,struct pipe_fence_handle * fence,uint64_t timeout)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
dd_screen_destroy(struct pipe_screen * _screen)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 *
ddebug_screen_create(struct pipe_screen * 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