2 * Copyright (c) 2017 Etnaviv Project
3 * Copyright (C) 2017 Zodiac Inflight Innovations
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:
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial portions
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.
25 * Rob Clark <robclark@freedesktop.org>
26 * Christian Gmeiner <christian.gmeiner@gmail.com>
29 #include "util/u_inlines.h"
30 #include "util/u_memory.h"
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"
41 * OCCLUSION_COUNTER and OCCLUSION_PREDICATE differ only in how they
46 occlusion_resume(struct etna_acc_query
*aq
, struct etna_context
*ctx
)
48 struct etna_resource
*rsc
= etna_resource(aq
->prsc
);
49 struct etna_reloc r
= {
51 .flags
= ETNA_RELOC_WRITE
54 if (aq
->samples
> 63) {
56 BUG("samples overflow");
59 r
.offset
= aq
->samples
* 8; /* 64bit value */
61 etna_set_state_reloc(ctx
->stream
, VIVS_GL_OCCLUSION_QUERY_ADDR
, &r
);
62 resource_written(ctx
, aq
->prsc
);
66 occlusion_suspend(struct etna_acc_query
*aq
, struct etna_context
*ctx
)
68 /* 0x1DF5E76 is the value used by blob - but any random value will work */
69 etna_set_state(ctx
->stream
, VIVS_GL_OCCLUSION_QUERY_CONTROL
, 0x1DF5E76);
70 resource_written(ctx
, aq
->prsc
);
74 occlusion_result(struct etna_acc_query
*aq
, void *buf
,
75 union pipe_query_result
*result
)
78 uint64_t *ptr
= (uint64_t *)buf
;
80 for (unsigned i
= 0; i
< aq
->samples
; i
++)
83 if (aq
->base
.type
== PIPE_QUERY_OCCLUSION_COUNTER
)
90 etna_acc_destroy_query(struct etna_context
*ctx
, struct etna_query
*q
)
92 struct etna_acc_query
*aq
= etna_acc_query(q
);
94 pipe_resource_reference(&aq
->prsc
, NULL
);
100 static const struct etna_acc_sample_provider occlusion_provider
= {
101 .suspend
= occlusion_suspend
,
102 .resume
= occlusion_resume
,
103 .result
= occlusion_result
,
107 realloc_query_bo(struct etna_context
*ctx
, struct etna_acc_query
*aq
)
109 struct etna_resource
*rsc
;
112 pipe_resource_reference(&aq
->prsc
, NULL
);
114 /* allocate resource with space for 64 * 64bit values */
115 aq
->prsc
= pipe_buffer_create(&ctx
->screen
->base
, PIPE_BIND_QUERY_BUFFER
,
118 /* don't assume the buffer is zero-initialized */
119 rsc
= etna_resource(aq
->prsc
);
121 etna_bo_cpu_prep(rsc
->bo
, DRM_ETNA_PREP_WRITE
);
123 map
= etna_bo_map(rsc
->bo
);
124 memset(map
, 0, 0x1000);
125 etna_bo_cpu_fini(rsc
->bo
);
129 etna_acc_begin_query(struct etna_context
*ctx
, struct etna_query
*q
)
131 struct etna_acc_query
*aq
= etna_acc_query(q
);
132 const struct etna_acc_sample_provider
*p
= aq
->provider
;
134 /* ->begin_query() discards previous results, so realloc bo */
135 realloc_query_bo(ctx
, aq
);
140 /* add to active list */
141 assert(list_is_empty(&aq
->node
));
142 list_addtail(&aq
->node
, &ctx
->active_acc_queries
);
148 etna_acc_end_query(struct etna_context
*ctx
, struct etna_query
*q
)
150 struct etna_acc_query
*aq
= etna_acc_query(q
);
151 const struct etna_acc_sample_provider
*p
= aq
->provider
;
156 /* remove from active list */
157 list_delinit(&aq
->node
);
161 etna_acc_get_query_result(struct etna_context
*ctx
, struct etna_query
*q
,
162 bool wait
, union pipe_query_result
*result
)
164 struct etna_acc_query
*aq
= etna_acc_query(q
);
165 struct etna_resource
*rsc
= etna_resource(aq
->prsc
);
166 const struct etna_acc_sample_provider
*p
= aq
->provider
;
168 assert(list_is_empty(&aq
->node
));
173 if (rsc
->status
& ETNA_PENDING_WRITE
) {
174 /* piglit spec@arb_occlusion_query@occlusion_query_conform
175 * test, and silly apps perhaps, get stuck in a loop trying
176 * to get query result forever with wait==false.. we don't
177 * wait to flush unnecessarily but we also don't want to
180 if (aq
->no_wait_cnt
++ > 5) {
181 ctx
->base
.flush(&ctx
->base
, NULL
, 0);
188 ret
= etna_bo_cpu_prep(rsc
->bo
, DRM_ETNA_PREP_READ
| DRM_ETNA_PREP_NOSYNC
);
192 etna_bo_cpu_fini(rsc
->bo
);
195 /* flush that GPU executes all query related actions */
196 ctx
->base
.flush(&ctx
->base
, NULL
, 0);
199 etna_bo_cpu_prep(rsc
->bo
, DRM_ETNA_PREP_READ
);
201 void *ptr
= etna_bo_map(rsc
->bo
);
202 p
->result(aq
, ptr
, result
);
205 etna_bo_cpu_fini(rsc
->bo
);
210 static const struct etna_query_funcs acc_query_funcs
= {
211 .destroy_query
= etna_acc_destroy_query
,
212 .begin_query
= etna_acc_begin_query
,
213 .end_query
= etna_acc_end_query
,
214 .get_query_result
= etna_acc_get_query_result
,
217 static inline const struct etna_acc_sample_provider
*
218 query_sample_provider(unsigned query_type
)
220 switch (query_type
) {
221 case PIPE_QUERY_OCCLUSION_COUNTER
:
223 case PIPE_QUERY_OCCLUSION_PREDICATE
:
225 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE
:
226 return &occlusion_provider
;
233 etna_acc_create_query(struct etna_context
*ctx
, unsigned query_type
)
235 struct etna_acc_query
*aq
;
236 struct etna_query
*q
;
237 const struct etna_acc_sample_provider
*p
;
239 p
= query_sample_provider(query_type
);
243 aq
= CALLOC_STRUCT(etna_acc_query
);
249 list_inithead(&aq
->node
);
252 q
->funcs
= &acc_query_funcs
;
253 q
->type
= query_type
;