xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/etnaviv/etnaviv_query_acc.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright (c) 2017 Etnaviv Project
3  * Copyright (C) 2017 Zodiac Inflight Innovations
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sub license,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the
13  * next paragraph) shall be included in all copies or substantial portions
14  * 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 NON-INFRINGEMENT. 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  *    Rob Clark <[email protected]>
26  *    Christian Gmeiner <[email protected]>
27  */
28 
29 #include "util/u_inlines.h"
30 #include "util/u_memory.h"
31 
32 #include "etnaviv_context.h"
33 #include "etnaviv_debug.h"
34 #include "etnaviv_emit.h"
35 #include "etnaviv_query_acc.h"
36 #include "etnaviv_screen.h"
37 
38 
39 extern const struct etna_acc_sample_provider occlusion_provider;
40 extern const struct etna_acc_sample_provider perfmon_provider;
41 
42 static const struct etna_acc_sample_provider *acc_sample_provider[] =
43 {
44    &occlusion_provider,
45    &perfmon_provider,
46 };
47 
48 static void
etna_acc_destroy_query(struct etna_context * ctx,struct etna_query * q)49 etna_acc_destroy_query(struct etna_context *ctx, struct etna_query *q)
50 {
51    struct etna_acc_query *aq = etna_acc_query(q);
52 
53    pipe_resource_reference(&aq->prsc, NULL);
54    list_del(&aq->node);
55 
56    FREE(aq);
57 }
58 
59 static void
realloc_query_bo(struct etna_context * ctx,struct etna_acc_query * aq)60 realloc_query_bo(struct etna_context *ctx, struct etna_acc_query *aq)
61 {
62    struct etna_resource *rsc;
63    void *map;
64 
65    pipe_resource_reference(&aq->prsc, NULL);
66 
67    aq->prsc = pipe_buffer_create(&ctx->screen->base, PIPE_BIND_QUERY_BUFFER,
68                                  0, 0x1000);
69 
70    /* don't assume the buffer is zero-initialized */
71    rsc = etna_resource(aq->prsc);
72 
73    etna_bo_cpu_prep(rsc->bo, DRM_ETNA_PREP_WRITE);
74 
75    map = etna_bo_map(rsc->bo);
76    memset(map, 0, 0x1000);
77    etna_bo_cpu_fini(rsc->bo);
78 }
79 
80 static void
etna_acc_begin_query(struct etna_context * ctx,struct etna_query * q)81 etna_acc_begin_query(struct etna_context *ctx, struct etna_query *q)
82 {
83    struct etna_acc_query *aq = etna_acc_query(q);
84    const struct etna_acc_sample_provider *p = aq->provider;
85 
86    /* ->begin_query() discards previous results, so realloc bo */
87    realloc_query_bo(ctx, aq);
88    aq->samples = 0;
89 
90    p->resume(aq, ctx);
91 
92    /* add to active list */
93    assert(list_is_empty(&aq->node));
94    list_addtail(&aq->node, &ctx->active_acc_queries);
95 }
96 
97 static void
etna_acc_end_query(struct etna_context * ctx,struct etna_query * q)98 etna_acc_end_query(struct etna_context *ctx, struct etna_query *q)
99 {
100    struct etna_acc_query *aq = etna_acc_query(q);
101    const struct etna_acc_sample_provider *p = aq->provider;
102 
103    p->suspend(aq, ctx);
104 
105    /* remove from active list */
106    list_delinit(&aq->node);
107 }
108 
109 static bool
etna_acc_get_query_result(struct etna_context * ctx,struct etna_query * q,bool wait,union pipe_query_result * result)110 etna_acc_get_query_result(struct etna_context *ctx, struct etna_query *q,
111                           bool wait, union pipe_query_result *result)
112 {
113    struct etna_acc_query *aq = etna_acc_query(q);
114    struct etna_resource *rsc = etna_resource(aq->prsc);
115    const struct etna_acc_sample_provider *p = aq->provider;
116    uint32_t prep_op = DRM_ETNA_PREP_READ;
117 
118    assert(list_is_empty(&aq->node));
119 
120    /* ARB_occlusion_query says:
121     *     "Querying the state for a given occlusion query forces that
122     *      occlusion query to complete within a finite amount of time."
123     *
124     * So, regardless of whether we are supposed to wait or not, we do need to
125     * flush now.
126     */
127    if (etna_resource_status(ctx, rsc) & ETNA_PENDING_WRITE)
128       etna_flush(&ctx->base, NULL, 0, true);
129 
130    if (!wait)
131       prep_op |= DRM_ETNA_PREP_NOSYNC;
132 
133    /* get the result */
134    int ret = etna_bo_cpu_prep(rsc->bo, prep_op);
135    if (ret)
136       return false;
137 
138    void *ptr = etna_bo_map(rsc->bo);
139    bool success = p->result(aq, ptr, result);
140 
141    etna_bo_cpu_fini(rsc->bo);
142 
143    return success;
144 }
145 
146 static const struct etna_query_funcs acc_query_funcs = {
147    .destroy_query = etna_acc_destroy_query,
148    .begin_query = etna_acc_begin_query,
149    .end_query = etna_acc_end_query,
150    .get_query_result = etna_acc_get_query_result,
151 };
152 
153 struct etna_query *
etna_acc_create_query(struct etna_context * ctx,unsigned query_type)154 etna_acc_create_query(struct etna_context *ctx, unsigned query_type)
155 {
156    const struct etna_acc_sample_provider *p = NULL;
157    struct etna_acc_query *aq;
158    struct etna_query *q;
159 
160    /* find a sample provide for the requested query type */
161    for (unsigned i = 0; i < ARRAY_SIZE(acc_sample_provider); i++) {
162       p = acc_sample_provider[i];
163 
164       if (p->supports(query_type))
165          break;
166       else
167          p = NULL;
168    }
169 
170    if (!p)
171       return NULL;
172 
173    aq = p->allocate(ctx, query_type);
174    if (!aq)
175       return NULL;
176 
177    aq->provider = p;
178 
179    list_inithead(&aq->node);
180 
181    q = &aq->base;
182    q->funcs = &acc_query_funcs;
183    q->type = query_type;
184 
185    return q;
186 }
187