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_hw.h"
36 #include "etnaviv_screen.h"
41 * OCCLUSION_COUNTER and OCCLUSION_PREDICATE differ only in how they
46 occlusion_start(struct etna_hw_query
*hq
, struct etna_context
*ctx
)
48 struct etna_resource
*rsc
= etna_resource(hq
->prsc
);
49 struct etna_reloc r
= {
51 .flags
= ETNA_RELOC_WRITE
54 if (hq
->samples
> 63) {
56 BUG("samples overflow");
59 r
.offset
= hq
->samples
* 8; /* 64bit value */
61 etna_set_state_reloc(ctx
->stream
, VIVS_GL_OCCLUSION_QUERY_ADDR
, &r
);
65 occlusion_stop(struct etna_hw_query
*hq
, struct etna_context
*ctx
)
67 /* 0x1DF5E76 is the value used by blob - but any random value will work */
68 etna_set_state(ctx
->stream
, VIVS_GL_OCCLUSION_QUERY_CONTROL
, 0x1DF5E76);
72 occlusion_suspend(struct etna_hw_query
*hq
, struct etna_context
*ctx
)
74 occlusion_stop(hq
, ctx
);
78 occlusion_resume(struct etna_hw_query
*hq
, struct etna_context
*ctx
)
81 occlusion_start(hq
, ctx
);
85 occlusion_result(struct etna_hw_query
*hq
, void *buf
,
86 union pipe_query_result
*result
)
89 uint64_t *ptr
= (uint64_t *)buf
;
91 for (unsigned i
= 0; i
<= hq
->samples
; i
++)
94 if (hq
->base
.type
== PIPE_QUERY_OCCLUSION_COUNTER
)
101 etna_hw_destroy_query(struct etna_context
*ctx
, struct etna_query
*q
)
103 struct etna_hw_query
*hq
= etna_hw_query(q
);
105 pipe_resource_reference(&hq
->prsc
, NULL
);
111 static const struct etna_hw_sample_provider occlusion_provider
= {
112 .start
= occlusion_start
,
113 .stop
= occlusion_stop
,
114 .suspend
= occlusion_suspend
,
115 .resume
= occlusion_resume
,
116 .result
= occlusion_result
,
120 realloc_query_bo(struct etna_context
*ctx
, struct etna_hw_query
*hq
)
122 struct etna_resource
*rsc
;
125 pipe_resource_reference(&hq
->prsc
, NULL
);
127 /* allocate resource with space for 64 * 64bit values */
128 hq
->prsc
= pipe_buffer_create(&ctx
->screen
->base
, PIPE_BIND_QUERY_BUFFER
,
131 /* don't assume the buffer is zero-initialized */
132 rsc
= etna_resource(hq
->prsc
);
134 etna_bo_cpu_prep(rsc
->bo
, DRM_ETNA_PREP_WRITE
);
136 map
= etna_bo_map(rsc
->bo
);
137 memset(map
, 0, 0x1000);
138 etna_bo_cpu_fini(rsc
->bo
);
142 etna_hw_begin_query(struct etna_context
*ctx
, struct etna_query
*q
)
144 struct etna_hw_query
*hq
= etna_hw_query(q
);
145 const struct etna_hw_sample_provider
*p
= hq
->provider
;
147 /* ->begin_query() discards previous results, so realloc bo */
148 realloc_query_bo(ctx
, hq
);
152 /* add to active list */
153 assert(list_empty(&hq
->node
));
154 list_addtail(&hq
->node
, &ctx
->active_hw_queries
);
160 etna_hw_end_query(struct etna_context
*ctx
, struct etna_query
*q
)
162 struct etna_hw_query
*hq
= etna_hw_query(q
);
163 const struct etna_hw_sample_provider
*p
= hq
->provider
;
167 /* remove from active list */
168 list_delinit(&hq
->node
);
172 etna_hw_get_query_result(struct etna_context
*ctx
, struct etna_query
*q
,
173 boolean wait
, union pipe_query_result
*result
)
175 struct etna_hw_query
*hq
= etna_hw_query(q
);
176 struct etna_resource
*rsc
= etna_resource(hq
->prsc
);
177 const struct etna_hw_sample_provider
*p
= hq
->provider
;
179 assert(LIST_IS_EMPTY(&hq
->node
));
184 if (rsc
->status
& ETNA_PENDING_WRITE
) {
185 /* piglit spec@arb_occlusion_query@occlusion_query_conform
186 * test, and silly apps perhaps, get stuck in a loop trying
187 * to get query result forever with wait==false.. we don't
188 * wait to flush unnecessarily but we also don't want to
191 if (hq
->no_wait_cnt
++ > 5)
192 ctx
->base
.flush(&ctx
->base
, NULL
, 0);
196 ret
= etna_bo_cpu_prep(rsc
->bo
, DRM_ETNA_PREP_READ
| DRM_ETNA_PREP_NOSYNC
);
200 etna_bo_cpu_fini(rsc
->bo
);
203 /* flush that GPU executes all query related actions */
204 ctx
->base
.flush(&ctx
->base
, NULL
, 0);
207 etna_bo_cpu_prep(rsc
->bo
, DRM_ETNA_PREP_READ
);
209 void *ptr
= etna_bo_map(rsc
->bo
);
210 p
->result(hq
, ptr
, result
);
212 etna_bo_cpu_fini(rsc
->bo
);
217 static const struct etna_query_funcs hw_query_funcs
= {
218 .destroy_query
= etna_hw_destroy_query
,
219 .begin_query
= etna_hw_begin_query
,
220 .end_query
= etna_hw_end_query
,
221 .get_query_result
= etna_hw_get_query_result
,
224 static inline const struct etna_hw_sample_provider
*
225 query_sample_provider(unsigned query_type
)
227 switch (query_type
) {
228 case PIPE_QUERY_OCCLUSION_COUNTER
:
230 case PIPE_QUERY_OCCLUSION_PREDICATE
:
232 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE
:
233 return &occlusion_provider
;
240 etna_hw_create_query(struct etna_context
*ctx
, unsigned query_type
)
242 struct etna_hw_query
*hq
;
243 struct etna_query
*q
;
244 const struct etna_hw_sample_provider
*p
;
246 p
= query_sample_provider(query_type
);
250 hq
= CALLOC_STRUCT(etna_hw_query
);
256 list_inithead(&hq
->node
);
259 q
->funcs
= &hw_query_funcs
;
260 q
->type
= query_type
;