Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
4358 Serge 1
/**************************************************************************
2
 *
3
 * Copyright 2013 Marek Olšák 
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 
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
}