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