1/*
2 * Copyright © 2014 Broadcom
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, sublicense,
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 next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * 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 NONINFRINGEMENT.  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 DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24/**
25 * Gallium query object support.
26 *
27 * The HW has native support for occlusion queries, with the query result
28 * being loaded and stored by the TLB unit. From a SW perspective, we have to
29 * be careful to make sure that the jobs that need to be tracking queries are
30 * bracketed by the start and end of counting, even across FBO transitions.
31 *
32 * For the transform feedback PRIMITIVES_GENERATED/WRITTEN queries, we have to
33 * do the calculations in software at draw time.
34 */
35
36#include "v3d_context.h"
37#include "broadcom/cle/v3d_packet_v33_pack.h"
38
39struct v3d_query
40{
41        enum pipe_query_type type;
42        struct v3d_bo *bo;
43
44        uint32_t start, end;
45};
46
47static struct pipe_query *
48v3d_create_query(struct pipe_context *pctx, unsigned query_type, unsigned index)
49{
50        struct v3d_query *q = calloc(1, sizeof(*q));
51
52        q->type = query_type;
53
54        /* Note that struct pipe_query isn't actually defined anywhere. */
55        return (struct pipe_query *)q;
56}
57
58static void
59v3d_destroy_query(struct pipe_context *pctx, struct pipe_query *query)
60{
61        struct v3d_query *q = (struct v3d_query *)query;
62
63        v3d_bo_unreference(&q->bo);
64        free(q);
65}
66
67static boolean
68v3d_begin_query(struct pipe_context *pctx, struct pipe_query *query)
69{
70        struct v3d_context *v3d = v3d_context(pctx);
71        struct v3d_query *q = (struct v3d_query *)query;
72
73        switch (q->type) {
74        case PIPE_QUERY_PRIMITIVES_GENERATED:
75                q->start = v3d->prims_generated;
76                break;
77        case PIPE_QUERY_PRIMITIVES_EMITTED:
78                q->start = v3d->tf_prims_generated;
79                break;
80        default:
81                q->bo = v3d_bo_alloc(v3d->screen, 4096, "query");
82
83                uint32_t *map = v3d_bo_map(q->bo);
84                *map = 0;
85                v3d->current_oq = q->bo;
86                v3d->dirty |= VC5_DIRTY_OQ;
87                break;
88        }
89
90        return true;
91}
92
93static bool
94v3d_end_query(struct pipe_context *pctx, struct pipe_query *query)
95{
96        struct v3d_context *v3d = v3d_context(pctx);
97        struct v3d_query *q = (struct v3d_query *)query;
98
99        switch (q->type) {
100        case PIPE_QUERY_PRIMITIVES_GENERATED:
101                q->end = v3d->prims_generated;
102                break;
103        case PIPE_QUERY_PRIMITIVES_EMITTED:
104                q->end = v3d->tf_prims_generated;
105                break;
106        default:
107                v3d->current_oq = NULL;
108                v3d->dirty |= VC5_DIRTY_OQ;
109                break;
110        }
111
112        return true;
113}
114
115static boolean
116v3d_get_query_result(struct pipe_context *pctx, struct pipe_query *query,
117                     boolean wait, union pipe_query_result *vresult)
118{
119        struct v3d_query *q = (struct v3d_query *)query;
120        uint32_t result = 0;
121
122        if (q->bo) {
123                /* XXX: Only flush the jobs using this BO. */
124                v3d_flush(pctx);
125
126                if (wait) {
127                        if (!v3d_bo_wait(q->bo, 0, "query"))
128                                return false;
129                } else {
130                        if (!v3d_bo_wait(q->bo, ~0ull, "query"))
131                                return false;
132                }
133
134                /* XXX: Sum up per-core values. */
135                uint32_t *map = v3d_bo_map(q->bo);
136                result = *map;
137
138                v3d_bo_unreference(&q->bo);
139        }
140
141        switch (q->type) {
142        case PIPE_QUERY_OCCLUSION_COUNTER:
143                vresult->u64 = result;
144                break;
145        case PIPE_QUERY_OCCLUSION_PREDICATE:
146        case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
147                vresult->b = result != 0;
148                break;
149        case PIPE_QUERY_PRIMITIVES_GENERATED:
150        case PIPE_QUERY_PRIMITIVES_EMITTED:
151                vresult->u64 = q->end - q->start;
152                break;
153        default:
154                unreachable("unsupported query type");
155        }
156
157        return true;
158}
159
160static void
161v3d_set_active_query_state(struct pipe_context *pctx, boolean enable)
162{
163        struct v3d_context *v3d = v3d_context(pctx);
164
165        v3d->active_queries = enable;
166        v3d->dirty |= VC5_DIRTY_OQ;
167        v3d->dirty |= VC5_DIRTY_STREAMOUT;
168}
169
170void
171v3d_query_init(struct pipe_context *pctx)
172{
173        pctx->create_query = v3d_create_query;
174        pctx->destroy_query = v3d_destroy_query;
175        pctx->begin_query = v3d_begin_query;
176        pctx->end_query = v3d_end_query;
177        pctx->get_query_result = v3d_get_query_result;
178        pctx->set_active_query_state = v3d_set_active_query_state;
179}
180
181