Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /**************************************************************************
  2.  *
  3.  * Copyright 2013 Marek Olšák <maraeo@gmail.com>
  4.  * All Rights Reserved.
  5.  *
  6.  * Permission is hereby granted, free of charge, to any person obtaining a
  7.  * copy of this software and associated documentation files (the
  8.  * "Software"), to deal in the Software without restriction, including
  9.  * without limitation the rights to use, copy, modify, merge, publish,
  10.  * distribute, sub license, and/or sell copies of the Software, and to
  11.  * permit persons to whom the Software is furnished to do so, subject to
  12.  * the following conditions:
  13.  *
  14.  * The above copyright notice and this permission notice (including the
  15.  * next paragraph) shall be included in all copies or substantial portions
  16.  * of the Software.
  17.  *
  18.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  19.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  20.  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
  21.  * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR
  22.  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  23.  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  24.  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  25.  *
  26.  **************************************************************************/
  27.  
  28. /* This file contains code for reading values from pipe queries
  29.  * for displaying on the HUD. To prevent stalls when reading queries, we
  30.  * keep a list of busy queries in a ring. We read only those queries which
  31.  * are idle.
  32.  */
  33.  
  34. #include "hud/hud_private.h"
  35. #include "pipe/p_screen.h"
  36. #include "os/os_time.h"
  37. #include "util/u_memory.h"
  38. #include <stdio.h>
  39.  
  40. #define NUM_QUERIES 8
  41.  
  42. struct query_info {
  43.    struct pipe_context *pipe;
  44.    unsigned query_type;
  45.    unsigned result_index; /* unit depends on query_type */
  46.  
  47.    /* Ring of queries. If a query is busy, we use another slot. */
  48.    struct pipe_query *query[NUM_QUERIES];
  49.    unsigned head, tail;
  50.    unsigned num_queries;
  51.  
  52.    uint64_t last_time;
  53.    uint64_t results_cumulative;
  54.    unsigned num_results;
  55. };
  56.  
  57. static void
  58. query_new_value(struct hud_graph *gr)
  59. {
  60.    struct query_info *info = gr->query_data;
  61.    struct pipe_context *pipe = info->pipe;
  62.    uint64_t now = os_time_get();
  63.  
  64.    if (info->last_time) {
  65.       pipe->end_query(pipe, info->query[info->head]);
  66.  
  67.       /* read query results */
  68.       while (1) {
  69.          struct pipe_query *query = info->query[info->tail];
  70.          union pipe_query_result result;
  71.          uint64_t *res64 = (uint64_t *)&result;
  72.  
  73.          if (pipe->get_query_result(pipe, query, FALSE, &result)) {
  74.             info->results_cumulative += res64[info->result_index];
  75.             info->num_results++;
  76.  
  77.             if (info->tail == info->head)
  78.                break;
  79.  
  80.             info->tail = (info->tail+1) % NUM_QUERIES;
  81.          }
  82.          else {
  83.             /* the oldest query is busy */
  84.             if ((info->head+1) % NUM_QUERIES == info->tail) {
  85.                /* all queries are busy, throw away the last query and create
  86.                 * a new one */
  87.                fprintf(stderr,
  88.                        "gallium_hud: all queries are busy after %i frames, "
  89.                        "can't add another query\n",
  90.                        NUM_QUERIES);
  91.                pipe->destroy_query(pipe, info->query[info->head]);
  92.                info->query[info->head] =
  93.                      pipe->create_query(pipe, info->query_type);
  94.             }
  95.             else {
  96.                /* the last query is busy, we need to add a new one we can use
  97.                 * for this frame */
  98.                info->head = (info->head+1) % NUM_QUERIES;
  99.                if (!info->query[info->head]) {
  100.                   info->query[info->head] =
  101.                         pipe->create_query(pipe, info->query_type);
  102.                }
  103.             }
  104.             break;
  105.          }
  106.       }
  107.  
  108.       if (info->num_results && info->last_time + gr->pane->period <= now) {
  109.          /* compute the average value across all frames */
  110.          hud_graph_add_value(gr, info->results_cumulative / info->num_results);
  111.  
  112.          info->last_time = now;
  113.          info->results_cumulative = 0;
  114.          info->num_results = 0;
  115.       }
  116.  
  117.       pipe->begin_query(pipe, info->query[info->head]);
  118.    }
  119.    else {
  120.       /* initialize */
  121.       info->last_time = now;
  122.       info->query[info->head] = pipe->create_query(pipe, info->query_type);
  123.       pipe->begin_query(pipe, info->query[info->head]);
  124.    }
  125. }
  126.  
  127. static void
  128. free_query_info(void *ptr)
  129. {
  130.    struct query_info *info = ptr;
  131.  
  132.    if (info->last_time) {
  133.       struct pipe_context *pipe = info->pipe;
  134.       int i;
  135.  
  136.       pipe->end_query(pipe, info->query[info->head]);
  137.  
  138.       for (i = 0; i < Elements(info->query); i++) {
  139.          if (info->query[i]) {
  140.             pipe->destroy_query(pipe, info->query[i]);
  141.          }
  142.       }
  143.    }
  144.    FREE(info);
  145. }
  146.  
  147. void
  148. hud_pipe_query_install(struct hud_pane *pane, struct pipe_context *pipe,
  149.                        const char *name, unsigned query_type,
  150.                        unsigned result_index,
  151.                        uint64_t max_value, boolean uses_byte_units)
  152. {
  153.    struct hud_graph *gr;
  154.    struct query_info *info;
  155.  
  156.    gr = CALLOC_STRUCT(hud_graph);
  157.    if (!gr)
  158.       return;
  159.  
  160.    strcpy(gr->name, name);
  161.    gr->query_data = CALLOC_STRUCT(query_info);
  162.    if (!gr->query_data) {
  163.       FREE(gr);
  164.       return;
  165.    }
  166.  
  167.    gr->query_new_value = query_new_value;
  168.    gr->free_query_data = free_query_info;
  169.  
  170.    info = gr->query_data;
  171.    info->pipe = pipe;
  172.    info->query_type = query_type;
  173.    info->result_index = result_index;
  174.  
  175.    hud_pane_add_graph(pane, gr);
  176.    if (pane->max_value < max_value)
  177.       hud_pane_set_max_value(pane, max_value);
  178.    if (uses_byte_units)
  179.       pane->uses_byte_units = TRUE;
  180. }
  181.  
  182. boolean
  183. hud_driver_query_install(struct hud_pane *pane, struct pipe_context *pipe,
  184.                          const char *name)
  185. {
  186.    struct pipe_screen *screen = pipe->screen;
  187.    struct pipe_driver_query_info query;
  188.    unsigned num_queries, i;
  189.    boolean found = FALSE;
  190.  
  191.    if (!screen->get_driver_query_info)
  192.       return FALSE;
  193.  
  194.    num_queries = screen->get_driver_query_info(screen, 0, NULL);
  195.  
  196.    for (i = 0; i < num_queries; i++) {
  197.       if (screen->get_driver_query_info(screen, i, &query) &&
  198.           strcmp(query.name, name) == 0) {
  199.          found = TRUE;
  200.          break;
  201.       }
  202.    }
  203.  
  204.    if (!found)
  205.       return FALSE;
  206.  
  207.    hud_pipe_query_install(pane, pipe, query.name, query.query_type, 0,
  208.                       query.max_value, query.uses_byte_units);
  209.    return TRUE;
  210. }
  211.