1/*
2 * Copyright (c) 2016 Etnaviv Project
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sub license,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the
12 * next paragraph) shall be included in all copies or substantial portions
13 * of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 *
23 * Authors:
24 *    Rob Clark <robclark@freedesktop.org>
25 *    Christian Gmeiner <christian.gmeiner@gmail.com>
26 */
27
28#include "util/os_time.h"
29#include "pipe/p_state.h"
30#include "util/u_memory.h"
31#include "util/u_string.h"
32
33#include "etnaviv_context.h"
34#include "etnaviv_query_sw.h"
35
36static void
37etna_sw_destroy_query(struct etna_context *ctx, struct etna_query *q)
38{
39   struct etna_sw_query *sq = etna_sw_query(q);
40
41   FREE(sq);
42}
43
44static uint64_t
45read_counter(struct etna_context *ctx, unsigned type)
46{
47   switch (type) {
48   case PIPE_QUERY_PRIMITIVES_EMITTED:
49      return ctx->stats.prims_emitted;
50   case ETNA_QUERY_DRAW_CALLS:
51      return ctx->stats.draw_calls;
52   case ETNA_QUERY_RS_OPERATIONS:
53      return ctx->stats.rs_operations;
54   }
55
56   return 0;
57}
58
59static boolean
60etna_sw_begin_query(struct etna_context *ctx, struct etna_query *q)
61{
62   struct etna_sw_query *sq = etna_sw_query(q);
63
64   sq->begin_value = read_counter(ctx, q->type);
65
66   return true;
67}
68
69static void
70etna_sw_end_query(struct etna_context *ctx, struct etna_query *q)
71{
72   struct etna_sw_query *sq = etna_sw_query(q);
73
74   sq->end_value = read_counter(ctx, q->type);
75}
76
77static boolean
78etna_sw_get_query_result(struct etna_context *ctx, struct etna_query *q,
79                         boolean wait, union pipe_query_result *result)
80{
81   struct etna_sw_query *sq = etna_sw_query(q);
82
83   result->u64 = sq->end_value - sq->begin_value;
84
85   return true;
86}
87
88static const struct etna_query_funcs sw_query_funcs = {
89   .destroy_query = etna_sw_destroy_query,
90   .begin_query = etna_sw_begin_query,
91   .end_query = etna_sw_end_query,
92   .get_query_result = etna_sw_get_query_result,
93};
94
95struct etna_query *
96etna_sw_create_query(struct etna_context *ctx, unsigned query_type)
97{
98   struct etna_sw_query *sq;
99   struct etna_query *q;
100
101   switch (query_type) {
102   case PIPE_QUERY_PRIMITIVES_EMITTED:
103   case ETNA_QUERY_DRAW_CALLS:
104   case ETNA_QUERY_RS_OPERATIONS:
105      break;
106   default:
107      return NULL;
108   }
109
110   sq = CALLOC_STRUCT(etna_sw_query);
111   if (!sq)
112      return NULL;
113
114   q = &sq->base;
115   q->funcs = &sw_query_funcs;
116   q->type = query_type;
117
118   return q;
119}
120
121static const struct pipe_driver_query_info list[] = {
122   {"prims-emitted", PIPE_QUERY_PRIMITIVES_EMITTED, { 0 }},
123   {"draw-calls", ETNA_QUERY_DRAW_CALLS, { 0 }},
124   {"rs-operations", ETNA_QUERY_RS_OPERATIONS, { 0 }},
125};
126
127int
128etna_sw_get_driver_query_info(struct pipe_screen *pscreen, unsigned index,
129                              struct pipe_driver_query_info *info)
130{
131   if (!info)
132      return ARRAY_SIZE(list);
133
134   if (index >= ARRAY_SIZE(list))
135      return 0;
136
137   *info = list[index];
138
139   return 1;
140}
141
142int
143etna_sw_get_driver_query_group_info(struct pipe_screen *pscreen,
144                                    unsigned index,
145                                    struct pipe_driver_query_group_info *info)
146{
147   if (!info)
148      return 1;
149
150   if (index != 0)
151      return 0;
152
153   info->name = "driver";
154   info->max_active_queries = ARRAY_SIZE(list);
155   info->num_queries = ARRAY_SIZE(list);
156
157   return 1;
158}
159