1/*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 2012-2013 LunarG, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 *    Chia-I Wu <olv@lunarg.com>
26 */
27
28#include "core/intel_winsys.h"
29
30#include "ilo_context.h"
31#include "ilo_cp.h"
32#include "ilo_draw.h"
33#include "ilo_query.h"
34
35static const struct {
36   bool (*init)(struct ilo_context *ilo, struct ilo_query *q);
37   void (*begin)(struct ilo_context *ilo, struct ilo_query *q);
38   void (*end)(struct ilo_context *ilo, struct ilo_query *q);
39   void (*process)(struct ilo_context *ilo, struct ilo_query *q);
40} ilo_query_table[PIPE_QUERY_TYPES] = {
41#define INFO(mod) {                    \
42   .init = ilo_init_ ## mod ## _query,         \
43   .begin = ilo_begin_ ## mod ## _query,       \
44   .end = ilo_end_ ## mod ## _query,           \
45   .process = ilo_process_ ## mod ## _query,   \
46}
47#define INFOX(prefix) { NULL, NULL, NULL, NULL, }
48
49   [PIPE_QUERY_OCCLUSION_COUNTER]      = INFO(draw),
50   [PIPE_QUERY_OCCLUSION_PREDICATE]    = INFO(draw),
51   [PIPE_QUERY_TIMESTAMP]              = INFO(draw),
52   [PIPE_QUERY_TIMESTAMP_DISJOINT]     = INFOX(draw),
53   [PIPE_QUERY_TIME_ELAPSED]           = INFO(draw),
54   [PIPE_QUERY_PRIMITIVES_GENERATED]   = INFO(draw),
55   [PIPE_QUERY_PRIMITIVES_EMITTED]     = INFO(draw),
56   [PIPE_QUERY_SO_STATISTICS]          = INFOX(draw),
57   [PIPE_QUERY_SO_OVERFLOW_PREDICATE]  = INFOX(draw),
58   [PIPE_QUERY_GPU_FINISHED]           = INFOX(draw),
59   [PIPE_QUERY_PIPELINE_STATISTICS]    = INFO(draw),
60
61#undef INFO
62#undef INFOX
63};
64
65static inline struct ilo_query *
66ilo_query(struct pipe_query *query)
67{
68   return (struct ilo_query *) query;
69}
70
71static struct pipe_query *
72ilo_create_query(struct pipe_context *pipe, unsigned query_type, unsigned index)
73{
74   struct ilo_query *q;
75
76   switch (query_type) {
77   case PIPE_QUERY_OCCLUSION_COUNTER:
78   case PIPE_QUERY_OCCLUSION_PREDICATE:
79   case PIPE_QUERY_TIMESTAMP:
80   case PIPE_QUERY_TIME_ELAPSED:
81   case PIPE_QUERY_PRIMITIVES_GENERATED:
82   case PIPE_QUERY_PRIMITIVES_EMITTED:
83   case PIPE_QUERY_PIPELINE_STATISTICS:
84      break;
85   default:
86      return NULL;
87   }
88
89   q = CALLOC_STRUCT(ilo_query);
90   if (!q)
91      return NULL;
92
93   q->type = query_type;
94   q->index = index;
95
96   list_inithead(&q->list);
97
98   if (!ilo_query_table[q->type].init(ilo_context(pipe), q)) {
99      FREE(q);
100      return NULL;
101   }
102
103   return (struct pipe_query *) q;
104}
105
106static void
107ilo_destroy_query(struct pipe_context *pipe, struct pipe_query *query)
108{
109   struct ilo_query *q = ilo_query(query);
110
111   intel_bo_unref(q->bo);
112   FREE(q);
113}
114
115static boolean
116ilo_begin_query(struct pipe_context *pipe, struct pipe_query *query)
117{
118   struct ilo_query *q = ilo_query(query);
119
120   if (q->active)
121      return false;
122
123   util_query_clear_result(&q->result, q->type);
124   q->used = 0;
125   q->active = true;
126
127   ilo_query_table[q->type].begin(ilo_context(pipe), q);
128   return true;
129}
130
131static bool
132ilo_end_query(struct pipe_context *pipe, struct pipe_query *query)
133{
134   struct ilo_query *q = ilo_query(query);
135
136   if (!q->active) {
137      /* require ilo_begin_query() first */
138      if (q->in_pairs)
139         return false;
140
141      ilo_begin_query(pipe, query);
142   }
143
144   q->active = false;
145
146   ilo_query_table[q->type].end(ilo_context(pipe), q);
147
148   return true;
149}
150
151/**
152 * Serialize the result.  The size of \p buf is
153 * sizeof(union pipe_query_result).
154 */
155static void
156query_serialize(const struct ilo_query *q, void *buf)
157{
158   switch (q->type) {
159   case PIPE_QUERY_OCCLUSION_COUNTER:
160   case PIPE_QUERY_TIMESTAMP:
161   case PIPE_QUERY_TIME_ELAPSED:
162   case PIPE_QUERY_PRIMITIVES_GENERATED:
163   case PIPE_QUERY_PRIMITIVES_EMITTED:
164      {
165         uint64_t *dst = buf;
166         dst[0] = q->result.u64;
167      }
168      break;
169   case PIPE_QUERY_OCCLUSION_PREDICATE:
170      {
171         uint64_t *dst = buf;
172         dst[0] = !!q->result.u64;
173      }
174      break;
175   case PIPE_QUERY_PIPELINE_STATISTICS:
176      {
177         const struct pipe_query_data_pipeline_statistics *stats =
178            &q->result.pipeline_statistics;
179         uint64_t *dst = buf;
180
181         dst[0] = stats->ia_vertices;
182         dst[1] = stats->ia_primitives;
183         dst[2] = stats->vs_invocations;
184         dst[3] = stats->gs_invocations;
185         dst[4] = stats->gs_primitives;
186         dst[5] = stats->c_invocations;
187         dst[6] = stats->c_primitives;
188         dst[7] = stats->ps_invocations;
189         dst[8] = stats->hs_invocations;
190         dst[9] = stats->ds_invocations;
191         dst[10] = stats->cs_invocations;
192      }
193      break;
194   default:
195      memset(buf, 0, sizeof(union pipe_query_result));
196      break;
197   }
198}
199
200static boolean
201ilo_get_query_result(struct pipe_context *pipe, struct pipe_query *query,
202                     boolean wait, union pipe_query_result *result)
203{
204   struct ilo_query *q = ilo_query(query);
205
206   if (q->active)
207      return false;
208
209   if (q->bo) {
210      struct ilo_cp *cp = ilo_context(pipe)->cp;
211
212      if (ilo_builder_has_reloc(&cp->builder, q->bo))
213         ilo_cp_submit(cp, "syncing for queries");
214
215      if (!wait && intel_bo_is_busy(q->bo))
216         return false;
217   }
218
219   ilo_query_table[q->type].process(ilo_context(pipe), q);
220
221   if (result)
222      query_serialize(q, (void *) result);
223
224   return true;
225}
226
227static void
228ilo_set_active_query_state(struct pipe_context *pipe, boolean enable)
229{
230}
231
232/**
233 * Initialize query-related functions.
234 */
235void
236ilo_init_query_functions(struct ilo_context *ilo)
237{
238   ilo->base.create_query = ilo_create_query;
239   ilo->base.destroy_query = ilo_destroy_query;
240   ilo->base.begin_query = ilo_begin_query;
241   ilo->base.end_query = ilo_end_query;
242   ilo->base.get_query_result = ilo_get_query_result;
243   ilo->base.set_active_query_state = ilo_set_active_query_state;
244}
245