ddebug: write out final driver log messages with GALLIUM_DDEBUG=always
[mesa.git] / src / gallium / drivers / ddebug / dd_draw.c
index 90ccf160e68994b30d03889bd94fbef4a7c22486..aec9332d903c1badbc50782dd7128276b491a3ac 100644 (file)
@@ -39,7 +39,7 @@
 #include <inttypes.h>
 
 
-static FILE *
+FILE *
 dd_get_file_stream(struct dd_screen *dscreen, unsigned apitrace_call_number)
 {
    struct pipe_screen *screen = dscreen->screen;
@@ -98,8 +98,13 @@ dd_num_active_viewports(struct dd_draw_state *dstate)
    else
       return 1;
 
-   tgsi_scan_shader(tokens, &info);
-   return info.writes_viewport_index ? PIPE_MAX_VIEWPORTS : 1;
+   if (tokens) {
+      tgsi_scan_shader(tokens, &info);
+      if (info.writes_viewport_index)
+         return PIPE_MAX_VIEWPORTS;
+   }
+
+   return 1;
 }
 
 #define COLOR_RESET    "\033[0m"
@@ -148,6 +153,12 @@ util_dump_uint(FILE *f, unsigned i)
    fprintf(f, "%u", i);
 }
 
+static void
+util_dump_int(FILE *f, int i)
+{
+   fprintf(f, "%d", i);
+}
+
 static void
 util_dump_hex(FILE *f, unsigned i)
 {
@@ -174,22 +185,12 @@ util_dump_color_union(FILE *f, const union pipe_color_union *color)
            color->ui[0], color->ui[1], color->ui[2], color->ui[3]);
 }
 
-static void
-util_dump_query(FILE *f, struct dd_query *query)
-{
-   if (query->type >= PIPE_QUERY_DRIVER_SPECIFIC)
-      fprintf(f, "PIPE_QUERY_DRIVER_SPECIFIC + %i",
-              query->type - PIPE_QUERY_DRIVER_SPECIFIC);
-   else
-      fprintf(f, "%s", util_dump_query_type(query->type, false));
-}
-
 static void
 dd_dump_render_condition(struct dd_draw_state *dstate, FILE *f)
 {
    if (dstate->render_cond.query) {
       fprintf(f, "render condition:\n");
-      DUMP_M(query, &dstate->render_cond, query);
+      DUMP_M(query_type, &dstate->render_cond, query->type);
       DUMP_M(uint, &dstate->render_cond, condition);
       DUMP_M(uint, &dstate->render_cond, mode);
       fprintf(f, "\n");
@@ -289,18 +290,15 @@ dd_dump_draw_vbo(struct dd_draw_state *dstate, struct pipe_draw_info *info, FILE
    int sh, i;
 
    DUMP(draw_info, info);
-   if (info->indexed) {
-      DUMP(index_buffer, &dstate->index_buffer);
-      if (dstate->index_buffer.buffer)
-         DUMP_M(resource, &dstate->index_buffer, buffer);
-   }
    if (info->count_from_stream_output)
       DUMP_M(stream_output_target, info,
              count_from_stream_output);
-   if (info->indirect)
-      DUMP_M(resource, info, indirect);
-   if (info->indirect_params)
-      DUMP_M(resource, info, indirect_params);
+   if (info->indirect) {
+      DUMP_M(resource, info, indirect->buffer);
+      if (info->indirect->indirect_draw_count)
+         DUMP_M(resource, info, indirect->indirect_draw_count);
+   }
+
    fprintf(f, "\n");
 
    /* TODO: dump active queries */
@@ -426,6 +424,18 @@ dd_dump_generate_mipmap(struct dd_draw_state *dstate, FILE *f)
    /* TODO */
 }
 
+static void
+dd_dump_get_query_result_resource(struct call_get_query_result_resource *info, FILE *f)
+{
+   fprintf(f, "%s:\n", __func__ + 8);
+   DUMP_M(query_type, info, query_type);
+   DUMP_M(uint, info, wait);
+   DUMP_M(query_value_type, info, result_type);
+   DUMP_M(int, info, index);
+   DUMP_M(resource, info, resource);
+   DUMP_M(uint, info, offset);
+}
+
 static void
 dd_dump_flush_resource(struct dd_draw_state *dstate, struct pipe_resource *res,
                        FILE *f)
@@ -500,7 +510,7 @@ dd_dump_call(FILE *f, struct dd_draw_state *state, struct dd_call *call)
 {
    switch (call->type) {
    case CALL_DRAW_VBO:
-      dd_dump_draw_vbo(state, &call->info.draw_vbo, f);
+      dd_dump_draw_vbo(state, &call->info.draw_vbo.draw, f);
       break;
    case CALL_LAUNCH_GRID:
       dd_dump_launch_grid(state, &call->info.launch_grid, f);
@@ -533,6 +543,9 @@ dd_dump_call(FILE *f, struct dd_draw_state *state, struct dd_call *call)
    case CALL_GENERATE_MIPMAP:
       dd_dump_generate_mipmap(state, f);
       break;
+   case CALL_GET_QUERY_RESULT_RESOURCE:
+      dd_dump_get_query_result_resource(&call->info.get_query_result_resource, f);
+      break;
    }
 }
 
@@ -548,6 +561,12 @@ dd_write_report(struct dd_context *dctx, struct dd_call *call, unsigned flags,
 
    dd_dump_call(f, &dctx->draw_state, call);
    dd_dump_driver_state(dctx, f, flags);
+
+   fprintf(f,"\n\n**************************************************"
+             "***************************\n");
+   fprintf(f, "Context Log:\n\n");
+   u_log_new_page_print(&dctx->log, f);
+
    if (dump_dmesg)
       dd_dump_dmesg(f);
    dd_close_file_stream(f);
@@ -601,10 +620,7 @@ dd_flush_and_handle_hang(struct dd_context *dctx,
       if (f) {
          fprintf(f, "dd: %s.\n", cause);
          dd_dump_driver_state(dctx, f,
-                              PIPE_DUMP_DEVICE_STATUS_REGISTERS |
-                              PIPE_DUMP_CURRENT_STATES |
-                              PIPE_DUMP_CURRENT_SHADERS |
-                              PIPE_DUMP_LAST_COMMAND_BUFFER);
+                              PIPE_DUMP_DEVICE_STATUS_REGISTERS);
          dd_dump_dmesg(f);
          dd_close_file_stream(f);
       }
@@ -619,9 +635,14 @@ dd_unreference_copy_of_call(struct dd_call *dst)
 {
    switch (dst->type) {
    case CALL_DRAW_VBO:
-      pipe_so_target_reference(&dst->info.draw_vbo.count_from_stream_output, NULL);
-      pipe_resource_reference(&dst->info.draw_vbo.indirect, NULL);
-      pipe_resource_reference(&dst->info.draw_vbo.indirect_params, NULL);
+      pipe_so_target_reference(&dst->info.draw_vbo.draw.count_from_stream_output, NULL);
+      pipe_resource_reference(&dst->info.draw_vbo.indirect.buffer, NULL);
+      pipe_resource_reference(&dst->info.draw_vbo.indirect.indirect_draw_count, NULL);
+      if (dst->info.draw_vbo.draw.index_size &&
+          !dst->info.draw_vbo.draw.has_user_indices)
+         pipe_resource_reference(&dst->info.draw_vbo.draw.index.resource, NULL);
+      else
+         dst->info.draw_vbo.draw.index.user = NULL;
       break;
    case CALL_LAUNCH_GRID:
       pipe_resource_reference(&dst->info.launch_grid.indirect, NULL);
@@ -651,6 +672,9 @@ dd_unreference_copy_of_call(struct dd_call *dst)
    case CALL_GENERATE_MIPMAP:
       pipe_resource_reference(&dst->info.generate_mipmap.res, NULL);
       break;
+   case CALL_GET_QUERY_RESULT_RESOURCE:
+      pipe_resource_reference(&dst->info.get_query_result_resource.resource, NULL);
+      break;
    }
 }
 
@@ -661,13 +685,30 @@ dd_copy_call(struct dd_call *dst, struct dd_call *src)
 
    switch (src->type) {
    case CALL_DRAW_VBO:
-      pipe_so_target_reference(&dst->info.draw_vbo.count_from_stream_output,
-                               src->info.draw_vbo.count_from_stream_output);
-      pipe_resource_reference(&dst->info.draw_vbo.indirect,
-                              src->info.draw_vbo.indirect);
-      pipe_resource_reference(&dst->info.draw_vbo.indirect_params,
-                              src->info.draw_vbo.indirect_params);
+      pipe_so_target_reference(&dst->info.draw_vbo.draw.count_from_stream_output,
+                               src->info.draw_vbo.draw.count_from_stream_output);
+      pipe_resource_reference(&dst->info.draw_vbo.indirect.buffer,
+                              src->info.draw_vbo.indirect.buffer);
+      pipe_resource_reference(&dst->info.draw_vbo.indirect.indirect_draw_count,
+                              src->info.draw_vbo.indirect.indirect_draw_count);
+
+      if (dst->info.draw_vbo.draw.index_size &&
+          !dst->info.draw_vbo.draw.has_user_indices)
+         pipe_resource_reference(&dst->info.draw_vbo.draw.index.resource, NULL);
+      else
+         dst->info.draw_vbo.draw.index.user = NULL;
+
+      if (src->info.draw_vbo.draw.index_size &&
+          !src->info.draw_vbo.draw.has_user_indices) {
+         pipe_resource_reference(&dst->info.draw_vbo.draw.index.resource,
+                                 src->info.draw_vbo.draw.index.resource);
+      }
+
       dst->info.draw_vbo = src->info.draw_vbo;
+      if (!src->info.draw_vbo.draw.indirect)
+         dst->info.draw_vbo.draw.indirect = NULL;
+      else
+         dst->info.draw_vbo.draw.indirect = &dst->info.draw_vbo.indirect;
       break;
    case CALL_LAUNCH_GRID:
       pipe_resource_reference(&dst->info.launch_grid.indirect,
@@ -711,6 +752,12 @@ dd_copy_call(struct dd_call *dst, struct dd_call *src)
                               src->info.generate_mipmap.res);
       dst->info.generate_mipmap = src->info.generate_mipmap;
       break;
+   case CALL_GET_QUERY_RESULT_RESOURCE:
+      pipe_resource_reference(&dst->info.get_query_result_resource.resource,
+                              src->info.get_query_result_resource.resource);
+      dst->info.get_query_result_resource = src->info.get_query_result_resource;
+      dst->info.get_query_result_resource.query = NULL;
+      break;
    }
 }
 
@@ -722,8 +769,6 @@ dd_init_copy_of_draw_state(struct dd_draw_state_copy *state)
    /* Just clear pointers to gallium objects. Don't clear the whole structure,
     * because it would kill performance with its size of 130 KB.
     */
-   memset(&state->base.index_buffer, 0,
-          sizeof(state->base.index_buffer));
    memset(state->base.vertex_buffers, 0,
           sizeof(state->base.vertex_buffers));
    memset(state->base.so_targets, 0,
@@ -761,8 +806,6 @@ dd_unreference_copy_of_draw_state(struct dd_draw_state_copy *state)
    struct dd_draw_state *dst = &state->base;
    unsigned i,j;
 
-   util_set_index_buffer(&dst->index_buffer, NULL);
-
    for (i = 0; i < ARRAY_SIZE(dst->vertex_buffers); i++)
       pipe_vertex_buffer_unreference(&dst->vertex_buffers[i]);
    for (i = 0; i < ARRAY_SIZE(dst->so_targets); i++)
@@ -798,8 +841,6 @@ dd_copy_draw_state(struct dd_draw_state *dst, struct dd_draw_state *src)
       dst->render_cond.query = NULL;
    }
 
-   util_set_index_buffer(&dst->index_buffer, &src->index_buffer);
-
    for (i = 0; i < ARRAY_SIZE(src->vertex_buffers); i++) {
       pipe_vertex_buffer_reference(&dst->vertex_buffers[i],
                                    &src->vertex_buffers[i]);
@@ -818,8 +859,12 @@ dd_copy_draw_state(struct dd_draw_state *dst, struct dd_draw_state *src)
 
       if (src->shaders[i]) {
          dst->shaders[i]->state.shader = src->shaders[i]->state.shader;
-         dst->shaders[i]->state.shader.tokens =
-            tgsi_dup_tokens(src->shaders[i]->state.shader.tokens);
+         if (src->shaders[i]->state.shader.tokens) {
+            dst->shaders[i]->state.shader.tokens =
+               tgsi_dup_tokens(src->shaders[i]->state.shader.tokens);
+         } else {
+            dst->shaders[i]->state.shader.ir.nir = NULL;
+         }
       } else {
          dst->shaders[i] = NULL;
       }
@@ -894,9 +939,9 @@ dd_free_record(struct dd_draw_record **record)
 {
    struct dd_draw_record *next = (*record)->next;
 
+   u_log_page_destroy((*record)->log_page);
    dd_unreference_copy_of_call(&(*record)->call);
    dd_unreference_copy_of_draw_state(&(*record)->draw_state);
-   FREE((*record)->driver_state_log);
    FREE(*record);
    *record = next;
 }
@@ -916,7 +961,11 @@ dd_dump_record(struct dd_context *dctx, struct dd_draw_record *record,
            (now - record->timestamp) / 1000);
 
    dd_dump_call(f, &record->draw_state.base, &record->call);
-   fprintf(f, "%s\n", record->driver_state_log);
+
+   fprintf(f,"\n\n**************************************************"
+             "***************************\n");
+   fprintf(f, "Context Log:\n\n");
+   u_log_page_print(record->log_page, f);
 
    dctx->pipe->dump_debug_state(dctx->pipe, f,
                                 PIPE_DUMP_DEVICE_STATUS_REGISTERS);
@@ -981,71 +1030,17 @@ dd_thread_pipelined_hang_detect(void *input)
    return 0;
 }
 
-static char *
-dd_get_driver_shader_log(struct dd_context *dctx)
-{
-#if defined(PIPE_OS_LINUX)
-   FILE *f;
-   char *buf;
-   int written_bytes;
-
-   if (!dctx->max_log_buffer_size)
-      dctx->max_log_buffer_size = 16 * 1024;
-
-   /* Keep increasing the buffer size until there is enough space.
-    *
-    * open_memstream can resize automatically, but it's VERY SLOW.
-    * fmemopen is much faster.
-    */
-   while (1) {
-      buf = malloc(dctx->max_log_buffer_size);
-      buf[0] = 0;
-
-      f = fmemopen(buf, dctx->max_log_buffer_size, "a");
-      if (!f) {
-         free(buf);
-         return NULL;
-      }
-
-      dd_dump_driver_state(dctx, f, PIPE_DUMP_CURRENT_SHADERS);
-      written_bytes = ftell(f);
-      fclose(f);
-
-      /* Return if the backing buffer is large enough. */
-      if (written_bytes < dctx->max_log_buffer_size - 1)
-         break;
-
-      /* Try again. */
-      free(buf);
-      dctx->max_log_buffer_size *= 2;
-   }
-
-   return buf;
-#else
-   /* Return an empty string. */
-   return (char*)calloc(1, 4);
-#endif
-}
-
 static void
 dd_pipelined_process_draw(struct dd_context *dctx, struct dd_call *call)
 {
    struct pipe_context *pipe = dctx->pipe;
    struct dd_draw_record *record;
-   char *log;
 
    /* Make a record of the draw call. */
    record = MALLOC_STRUCT(dd_draw_record);
    if (!record)
       return;
 
-   /* Create the log. */
-   log = dd_get_driver_shader_log(dctx);
-   if (!log) {
-      FREE(record);
-      return;
-   }
-
    /* Update the fence with the GPU.
     *
     * radeonsi/clear_buffer waits in the command processor until shaders are
@@ -1058,7 +1053,7 @@ dd_pipelined_process_draw(struct dd_context *dctx, struct dd_call *call)
    /* Initialize the record. */
    record->timestamp = os_time_get();
    record->sequence_no = dctx->sequence_no;
-   record->driver_state_log = log;
+   record->log_page = u_log_new_page(&dctx->log);
 
    memset(&record->call, 0, sizeof(record->call));
    dd_copy_call(&record->call, call);
@@ -1120,14 +1115,13 @@ dd_after_draw(struct dd_context *dctx, struct dd_call *call)
          if (!dscreen->no_flush &&
             dd_flush_and_check_hang(dctx, NULL, 0)) {
             dd_write_report(dctx, call,
-                         PIPE_DUMP_DEVICE_STATUS_REGISTERS |
-                         PIPE_DUMP_CURRENT_STATES |
-                         PIPE_DUMP_CURRENT_SHADERS |
-                         PIPE_DUMP_LAST_COMMAND_BUFFER,
+                         PIPE_DUMP_DEVICE_STATUS_REGISTERS,
                          true);
 
             /* Terminate the process to prevent future hangs. */
             dd_kill_process();
+         } else {
+            u_log_page_destroy(u_log_new_page(&dctx->log));
          }
          break;
       case DD_DETECT_HANGS_PIPELINED:
@@ -1136,21 +1130,16 @@ dd_after_draw(struct dd_context *dctx, struct dd_call *call)
       case DD_DUMP_ALL_CALLS:
          if (!dscreen->no_flush)
             pipe->flush(pipe, NULL, 0);
-         dd_write_report(dctx, call,
-                         PIPE_DUMP_CURRENT_STATES |
-                         PIPE_DUMP_CURRENT_SHADERS |
-                         PIPE_DUMP_LAST_COMMAND_BUFFER,
-                         false);
+         dd_write_report(dctx, call, 0, false);
          break;
       case DD_DUMP_APITRACE_CALL:
          if (dscreen->apitrace_dump_call ==
              dctx->draw_state.apitrace_call_number) {
-            dd_write_report(dctx, call,
-                            PIPE_DUMP_CURRENT_STATES |
-                            PIPE_DUMP_CURRENT_SHADERS,
-                            false);
+            dd_write_report(dctx, call, 0, false);
             /* No need to continue. */
             exit(0);
+         } else {
+            u_log_page_destroy(u_log_new_page(&dctx->log));
          }
          break;
       default:
@@ -1173,7 +1162,13 @@ dd_context_draw_vbo(struct pipe_context *_pipe,
    struct dd_call call;
 
    call.type = CALL_DRAW_VBO;
-   call.info.draw_vbo = *info;
+   call.info.draw_vbo.draw = *info;
+   if (info->indirect) {
+      call.info.draw_vbo.indirect = *info->indirect;
+      call.info.draw_vbo.draw.indirect = &call.info.draw_vbo.indirect;
+   } else {
+      memset(&call.info.draw_vbo.indirect, 0, sizeof(*info->indirect));
+   }
 
    dd_before_draw(dctx);
    pipe->draw_vbo(pipe, info);
@@ -1268,6 +1263,39 @@ dd_context_generate_mipmap(struct pipe_context *_pipe,
    return result;
 }
 
+static void
+dd_context_get_query_result_resource(struct pipe_context *_pipe,
+                                     struct pipe_query *query,
+                                     boolean wait,
+                                     enum pipe_query_value_type result_type,
+                                     int index,
+                                     struct pipe_resource *resource,
+                                     unsigned offset)
+{
+   struct dd_context *dctx = dd_context(_pipe);
+   struct dd_query *dquery = dd_query(query);
+   struct pipe_context *pipe = dctx->pipe;
+   struct dd_call call;
+
+   call.type = CALL_GET_QUERY_RESULT_RESOURCE;
+   call.info.get_query_result_resource.query = query;
+   call.info.get_query_result_resource.wait = wait;
+   call.info.get_query_result_resource.result_type = result_type;
+   call.info.get_query_result_resource.index = index;
+   call.info.get_query_result_resource.resource = resource;
+   call.info.get_query_result_resource.offset = offset;
+
+   /* In pipelined mode, the query may be deleted by the time we need to
+    * print it.
+    */
+   call.info.get_query_result_resource.query_type = dquery->type;
+
+   dd_before_draw(dctx);
+   pipe->get_query_result_resource(pipe, dquery->query, wait,
+                                   result_type, index, resource, offset);
+   dd_after_draw(dctx, &call);
+}
+
 static void
 dd_context_flush_resource(struct pipe_context *_pipe,
                           struct pipe_resource *resource)
@@ -1398,4 +1426,5 @@ dd_init_draw_functions(struct dd_context *dctx)
    CTX_INIT(clear_texture);
    CTX_INIT(flush_resource);
    CTX_INIT(generate_mipmap);
+   CTX_INIT(get_query_result_resource);
 }