1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2014 Broadcom
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21bf215546Sopenharmony_ci * IN THE SOFTWARE.
22bf215546Sopenharmony_ci */
23bf215546Sopenharmony_ci
24bf215546Sopenharmony_ci/**
25bf215546Sopenharmony_ci * Gallium query object support.
26bf215546Sopenharmony_ci *
27bf215546Sopenharmony_ci * The HW has native support for occlusion queries, with the query result
28bf215546Sopenharmony_ci * being loaded and stored by the TLB unit. From a SW perspective, we have to
29bf215546Sopenharmony_ci * be careful to make sure that the jobs that need to be tracking queries are
30bf215546Sopenharmony_ci * bracketed by the start and end of counting, even across FBO transitions.
31bf215546Sopenharmony_ci *
32bf215546Sopenharmony_ci * For the transform feedback PRIMITIVES_GENERATED/WRITTEN queries, we have to
33bf215546Sopenharmony_ci * do the calculations in software at draw time.
34bf215546Sopenharmony_ci */
35bf215546Sopenharmony_ci
36bf215546Sopenharmony_ci#include "v3d_query.h"
37bf215546Sopenharmony_ci
38bf215546Sopenharmony_cistruct v3d_query_pipe
39bf215546Sopenharmony_ci{
40bf215546Sopenharmony_ci        struct v3d_query base;
41bf215546Sopenharmony_ci
42bf215546Sopenharmony_ci        enum pipe_query_type type;
43bf215546Sopenharmony_ci        struct v3d_bo *bo;
44bf215546Sopenharmony_ci
45bf215546Sopenharmony_ci        uint32_t start, end;
46bf215546Sopenharmony_ci};
47bf215546Sopenharmony_ci
48bf215546Sopenharmony_cistatic void
49bf215546Sopenharmony_civ3d_destroy_query_pipe(struct v3d_context *v3d, struct v3d_query *query)
50bf215546Sopenharmony_ci{
51bf215546Sopenharmony_ci        struct v3d_query_pipe *pquery = (struct v3d_query_pipe *)query;
52bf215546Sopenharmony_ci
53bf215546Sopenharmony_ci        v3d_bo_unreference(&pquery->bo);
54bf215546Sopenharmony_ci        free(pquery);
55bf215546Sopenharmony_ci}
56bf215546Sopenharmony_ci
57bf215546Sopenharmony_cistatic bool
58bf215546Sopenharmony_civ3d_begin_query_pipe(struct v3d_context *v3d, struct v3d_query *query)
59bf215546Sopenharmony_ci{
60bf215546Sopenharmony_ci        struct v3d_query_pipe *pquery = (struct v3d_query_pipe *)query;
61bf215546Sopenharmony_ci
62bf215546Sopenharmony_ci        switch (pquery->type) {
63bf215546Sopenharmony_ci        case PIPE_QUERY_PRIMITIVES_GENERATED:
64bf215546Sopenharmony_ci                /* If we are using PRIMITIVE_COUNTS_FEEDBACK to retrieve
65bf215546Sopenharmony_ci                 * primitive counts from the GPU (which we need when a GS
66bf215546Sopenharmony_ci                 * is present), then we need to update our counters now
67bf215546Sopenharmony_ci                 * to discard any primitives generated before this.
68bf215546Sopenharmony_ci                 */
69bf215546Sopenharmony_ci                if (v3d->prog.gs)
70bf215546Sopenharmony_ci                        v3d_update_primitive_counters(v3d);
71bf215546Sopenharmony_ci                pquery->start = v3d->prims_generated;
72bf215546Sopenharmony_ci                v3d->n_primitives_generated_queries_in_flight++;
73bf215546Sopenharmony_ci                break;
74bf215546Sopenharmony_ci        case PIPE_QUERY_PRIMITIVES_EMITTED:
75bf215546Sopenharmony_ci                /* If we are inside transform feedback we need to update the
76bf215546Sopenharmony_ci                 * primitive counts to skip primitives recorded before this.
77bf215546Sopenharmony_ci                 */
78bf215546Sopenharmony_ci                if (v3d->streamout.num_targets > 0)
79bf215546Sopenharmony_ci                        v3d_update_primitive_counters(v3d);
80bf215546Sopenharmony_ci                pquery->start = v3d->tf_prims_generated;
81bf215546Sopenharmony_ci                break;
82bf215546Sopenharmony_ci        case PIPE_QUERY_OCCLUSION_COUNTER:
83bf215546Sopenharmony_ci        case PIPE_QUERY_OCCLUSION_PREDICATE:
84bf215546Sopenharmony_ci        case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
85bf215546Sopenharmony_ci                v3d_bo_unreference(&pquery->bo);
86bf215546Sopenharmony_ci                pquery->bo = v3d_bo_alloc(v3d->screen, 4096, "query");
87bf215546Sopenharmony_ci                uint32_t *map = v3d_bo_map(pquery->bo);
88bf215546Sopenharmony_ci                *map = 0;
89bf215546Sopenharmony_ci
90bf215546Sopenharmony_ci                v3d->current_oq = pquery->bo;
91bf215546Sopenharmony_ci                v3d->dirty |= V3D_DIRTY_OQ;
92bf215546Sopenharmony_ci                break;
93bf215546Sopenharmony_ci        default:
94bf215546Sopenharmony_ci                unreachable("unsupported query type");
95bf215546Sopenharmony_ci        }
96bf215546Sopenharmony_ci
97bf215546Sopenharmony_ci        return true;
98bf215546Sopenharmony_ci}
99bf215546Sopenharmony_ci
100bf215546Sopenharmony_cistatic bool
101bf215546Sopenharmony_civ3d_end_query_pipe(struct v3d_context *v3d, struct v3d_query *query)
102bf215546Sopenharmony_ci{
103bf215546Sopenharmony_ci        struct v3d_query_pipe *pquery = (struct v3d_query_pipe *)query;
104bf215546Sopenharmony_ci
105bf215546Sopenharmony_ci        switch (pquery->type) {
106bf215546Sopenharmony_ci        case PIPE_QUERY_PRIMITIVES_GENERATED:
107bf215546Sopenharmony_ci                /* If we are using PRIMITIVE_COUNTS_FEEDBACK to retrieve
108bf215546Sopenharmony_ci                 * primitive counts from the GPU (which we need when a GS
109bf215546Sopenharmony_ci                 * is present), then we need to update our counters now.
110bf215546Sopenharmony_ci                 */
111bf215546Sopenharmony_ci                if (v3d->prog.gs)
112bf215546Sopenharmony_ci                        v3d_update_primitive_counters(v3d);
113bf215546Sopenharmony_ci                pquery->end = v3d->prims_generated;
114bf215546Sopenharmony_ci                v3d->n_primitives_generated_queries_in_flight--;
115bf215546Sopenharmony_ci                break;
116bf215546Sopenharmony_ci        case PIPE_QUERY_PRIMITIVES_EMITTED:
117bf215546Sopenharmony_ci                /* If transform feedback has ended, then we have already
118bf215546Sopenharmony_ci                 * updated the primitive counts at glEndTransformFeedback()
119bf215546Sopenharmony_ci                 * time. Otherwise, we have to do it now.
120bf215546Sopenharmony_ci                 */
121bf215546Sopenharmony_ci                if (v3d->streamout.num_targets > 0)
122bf215546Sopenharmony_ci                        v3d_update_primitive_counters(v3d);
123bf215546Sopenharmony_ci                pquery->end = v3d->tf_prims_generated;
124bf215546Sopenharmony_ci                break;
125bf215546Sopenharmony_ci        case PIPE_QUERY_OCCLUSION_COUNTER:
126bf215546Sopenharmony_ci        case PIPE_QUERY_OCCLUSION_PREDICATE:
127bf215546Sopenharmony_ci        case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
128bf215546Sopenharmony_ci                v3d->current_oq = NULL;
129bf215546Sopenharmony_ci                v3d->dirty |= V3D_DIRTY_OQ;
130bf215546Sopenharmony_ci                break;
131bf215546Sopenharmony_ci        default:
132bf215546Sopenharmony_ci                unreachable("unsupported query type");
133bf215546Sopenharmony_ci        }
134bf215546Sopenharmony_ci
135bf215546Sopenharmony_ci        return true;
136bf215546Sopenharmony_ci}
137bf215546Sopenharmony_ci
138bf215546Sopenharmony_cistatic bool
139bf215546Sopenharmony_civ3d_get_query_result_pipe(struct v3d_context *v3d, struct v3d_query *query,
140bf215546Sopenharmony_ci                          bool wait, union pipe_query_result *vresult)
141bf215546Sopenharmony_ci{
142bf215546Sopenharmony_ci        struct v3d_query_pipe *pquery = (struct v3d_query_pipe *)query;
143bf215546Sopenharmony_ci        uint32_t result = 0;
144bf215546Sopenharmony_ci
145bf215546Sopenharmony_ci        if (pquery->bo) {
146bf215546Sopenharmony_ci                v3d_flush_jobs_using_bo(v3d, pquery->bo);
147bf215546Sopenharmony_ci
148bf215546Sopenharmony_ci                if (wait) {
149bf215546Sopenharmony_ci                        if (!v3d_bo_wait(pquery->bo, ~0ull, "query"))
150bf215546Sopenharmony_ci                                return false;
151bf215546Sopenharmony_ci                } else {
152bf215546Sopenharmony_ci                        if (!v3d_bo_wait(pquery->bo, 0, "query"))
153bf215546Sopenharmony_ci                                return false;
154bf215546Sopenharmony_ci                }
155bf215546Sopenharmony_ci
156bf215546Sopenharmony_ci                /* XXX: Sum up per-core values. */
157bf215546Sopenharmony_ci                uint32_t *map = v3d_bo_map(pquery->bo);
158bf215546Sopenharmony_ci                result = *map;
159bf215546Sopenharmony_ci
160bf215546Sopenharmony_ci                v3d_bo_unreference(&pquery->bo);
161bf215546Sopenharmony_ci        }
162bf215546Sopenharmony_ci
163bf215546Sopenharmony_ci        switch (pquery->type) {
164bf215546Sopenharmony_ci        case PIPE_QUERY_OCCLUSION_COUNTER:
165bf215546Sopenharmony_ci                vresult->u64 = result;
166bf215546Sopenharmony_ci                break;
167bf215546Sopenharmony_ci        case PIPE_QUERY_OCCLUSION_PREDICATE:
168bf215546Sopenharmony_ci        case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
169bf215546Sopenharmony_ci                vresult->b = result != 0;
170bf215546Sopenharmony_ci                break;
171bf215546Sopenharmony_ci        case PIPE_QUERY_PRIMITIVES_GENERATED:
172bf215546Sopenharmony_ci        case PIPE_QUERY_PRIMITIVES_EMITTED:
173bf215546Sopenharmony_ci                vresult->u64 = pquery->end - pquery->start;
174bf215546Sopenharmony_ci                break;
175bf215546Sopenharmony_ci        default:
176bf215546Sopenharmony_ci                unreachable("unsupported query type");
177bf215546Sopenharmony_ci        }
178bf215546Sopenharmony_ci
179bf215546Sopenharmony_ci        return true;
180bf215546Sopenharmony_ci}
181bf215546Sopenharmony_ci
182bf215546Sopenharmony_cistatic const struct v3d_query_funcs pipe_query_funcs = {
183bf215546Sopenharmony_ci        .destroy_query = v3d_destroy_query_pipe,
184bf215546Sopenharmony_ci        .begin_query = v3d_begin_query_pipe,
185bf215546Sopenharmony_ci        .end_query = v3d_end_query_pipe,
186bf215546Sopenharmony_ci        .get_query_result = v3d_get_query_result_pipe,
187bf215546Sopenharmony_ci};
188bf215546Sopenharmony_ci
189bf215546Sopenharmony_cistruct pipe_query *
190bf215546Sopenharmony_civ3d_create_query_pipe(struct v3d_context *v3d, unsigned query_type, unsigned index)
191bf215546Sopenharmony_ci{
192bf215546Sopenharmony_ci        if (query_type >= PIPE_QUERY_DRIVER_SPECIFIC)
193bf215546Sopenharmony_ci                return NULL;
194bf215546Sopenharmony_ci
195bf215546Sopenharmony_ci        struct v3d_query_pipe *pquery = calloc(1, sizeof(*pquery));
196bf215546Sopenharmony_ci        struct v3d_query *query = &pquery->base;
197bf215546Sopenharmony_ci
198bf215546Sopenharmony_ci        pquery->type = query_type;
199bf215546Sopenharmony_ci        query->funcs = &pipe_query_funcs;
200bf215546Sopenharmony_ci
201bf215546Sopenharmony_ci        /* Note that struct pipe_query isn't actually defined anywhere. */
202bf215546Sopenharmony_ci        return (struct pipe_query *)query;
203bf215546Sopenharmony_ci}
204