• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**************************************************************************
2  *
3  * Copyright 2007 VMware, Inc.
4  * Copyright 2010 VMware, Inc.
5  * All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the
9  * "Software"), to deal in the Software without restriction, including
10  * without limitation the rights to use, copy, modify, merge, publish,
11  * distribute, sub license, and/or sell copies of the Software, and to
12  * permit persons to whom the Software is furnished to do so, subject to
13  * the following conditions:
14  *
15  * The above copyright notice and this permission notice (including the
16  * next paragraph) shall be included in all copies or substantial portions
17  * of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22  * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR
23  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26  *
27  **************************************************************************/
28 
29 /* Authors:
30  *    Keith Whitwell, Qicheng Christopher Li, Brian Paul
31  */
32 
33 #include "draw/draw_context.h"
34 #include "pipe/p_defines.h"
35 #include "util/u_memory.h"
36 #include "util/os_time.h"
37 #include "lp_context.h"
38 #include "lp_flush.h"
39 #include "lp_fence.h"
40 #include "lp_query.h"
41 #include "lp_screen.h"
42 #include "lp_state.h"
43 #include "lp_rast.h"
44 
45 
llvmpipe_query(struct pipe_query * p)46 static struct llvmpipe_query *llvmpipe_query( struct pipe_query *p )
47 {
48    return (struct llvmpipe_query *)p;
49 }
50 
51 static struct pipe_query *
llvmpipe_create_query(struct pipe_context * pipe,unsigned type,unsigned index)52 llvmpipe_create_query(struct pipe_context *pipe,
53                       unsigned type,
54                       unsigned index)
55 {
56    struct llvmpipe_query *pq;
57 
58    assert(type < PIPE_QUERY_TYPES);
59 
60    pq = CALLOC_STRUCT( llvmpipe_query );
61 
62    if (pq) {
63       pq->type = type;
64    }
65 
66    return (struct pipe_query *) pq;
67 }
68 
69 
70 static void
llvmpipe_destroy_query(struct pipe_context * pipe,struct pipe_query * q)71 llvmpipe_destroy_query(struct pipe_context *pipe, struct pipe_query *q)
72 {
73    struct llvmpipe_query *pq = llvmpipe_query(q);
74 
75    /* Ideally we would refcount queries & not get destroyed until the
76     * last scene had finished with us.
77     */
78    if (pq->fence) {
79       if (!lp_fence_issued(pq->fence))
80          llvmpipe_flush(pipe, NULL, __FUNCTION__);
81 
82       if (!lp_fence_signalled(pq->fence))
83          lp_fence_wait(pq->fence);
84 
85       lp_fence_reference(&pq->fence, NULL);
86    }
87 
88    FREE(pq);
89 }
90 
91 
92 static boolean
llvmpipe_get_query_result(struct pipe_context * pipe,struct pipe_query * q,boolean wait,union pipe_query_result * vresult)93 llvmpipe_get_query_result(struct pipe_context *pipe,
94                           struct pipe_query *q,
95                           boolean wait,
96                           union pipe_query_result *vresult)
97 {
98    struct llvmpipe_screen *screen = llvmpipe_screen(pipe->screen);
99    unsigned num_threads = MAX2(1, screen->num_threads);
100    struct llvmpipe_query *pq = llvmpipe_query(q);
101    uint64_t *result = (uint64_t *)vresult;
102    int i;
103 
104    if (pq->fence) {
105       /* only have a fence if there was a scene */
106       if (!lp_fence_signalled(pq->fence)) {
107          if (!lp_fence_issued(pq->fence))
108             llvmpipe_flush(pipe, NULL, __FUNCTION__);
109 
110          if (!wait)
111             return FALSE;
112 
113          lp_fence_wait(pq->fence);
114       }
115    }
116 
117    /* Sum the results from each of the threads:
118     */
119    *result = 0;
120 
121    switch (pq->type) {
122    case PIPE_QUERY_OCCLUSION_COUNTER:
123       for (i = 0; i < num_threads; i++) {
124          *result += pq->end[i];
125       }
126       break;
127    case PIPE_QUERY_OCCLUSION_PREDICATE:
128    case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
129       for (i = 0; i < num_threads; i++) {
130          /* safer (still not guaranteed) when there's an overflow */
131          vresult->b = vresult->b || pq->end[i];
132       }
133       break;
134    case PIPE_QUERY_TIMESTAMP:
135       for (i = 0; i < num_threads; i++) {
136          if (pq->end[i] > *result) {
137             *result = pq->end[i];
138          }
139       }
140       break;
141    case PIPE_QUERY_TIMESTAMP_DISJOINT: {
142       struct pipe_query_data_timestamp_disjoint *td =
143          (struct pipe_query_data_timestamp_disjoint *)vresult;
144       /* os_get_time_nano return nanoseconds */
145       td->frequency = UINT64_C(1000000000);
146       td->disjoint = FALSE;
147    }
148       break;
149    case PIPE_QUERY_GPU_FINISHED:
150       vresult->b = TRUE;
151       break;
152    case PIPE_QUERY_PRIMITIVES_GENERATED:
153       *result = pq->num_primitives_generated;
154       break;
155    case PIPE_QUERY_PRIMITIVES_EMITTED:
156       *result = pq->num_primitives_written;
157       break;
158    case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
159    case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
160       vresult->b = pq->num_primitives_generated > pq->num_primitives_written;
161       break;
162    case PIPE_QUERY_SO_STATISTICS: {
163       struct pipe_query_data_so_statistics *stats =
164          (struct pipe_query_data_so_statistics *)vresult;
165       stats->num_primitives_written = pq->num_primitives_written;
166       stats->primitives_storage_needed = pq->num_primitives_generated;
167    }
168       break;
169    case PIPE_QUERY_PIPELINE_STATISTICS: {
170       struct pipe_query_data_pipeline_statistics *stats =
171          (struct pipe_query_data_pipeline_statistics *)vresult;
172       /* only ps_invocations come from binned query */
173       for (i = 0; i < num_threads; i++) {
174          pq->stats.ps_invocations += pq->end[i];
175       }
176       pq->stats.ps_invocations *= LP_RASTER_BLOCK_SIZE * LP_RASTER_BLOCK_SIZE;
177       *stats = pq->stats;
178    }
179       break;
180    default:
181       assert(0);
182       break;
183    }
184 
185    return TRUE;
186 }
187 
188 
189 static boolean
llvmpipe_begin_query(struct pipe_context * pipe,struct pipe_query * q)190 llvmpipe_begin_query(struct pipe_context *pipe, struct pipe_query *q)
191 {
192    struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
193    struct llvmpipe_query *pq = llvmpipe_query(q);
194 
195    /* Check if the query is already in the scene.  If so, we need to
196     * flush the scene now.  Real apps shouldn't re-use a query in a
197     * frame of rendering.
198     */
199    if (pq->fence && !lp_fence_issued(pq->fence)) {
200       llvmpipe_finish(pipe, __FUNCTION__);
201    }
202 
203 
204    memset(pq->start, 0, sizeof(pq->start));
205    memset(pq->end, 0, sizeof(pq->end));
206    lp_setup_begin_query(llvmpipe->setup, pq);
207 
208    switch (pq->type) {
209    case PIPE_QUERY_PRIMITIVES_EMITTED:
210       pq->num_primitives_written = llvmpipe->so_stats.num_primitives_written;
211       break;
212    case PIPE_QUERY_PRIMITIVES_GENERATED:
213       pq->num_primitives_generated = llvmpipe->so_stats.primitives_storage_needed;
214       break;
215    case PIPE_QUERY_SO_STATISTICS:
216       pq->num_primitives_written = llvmpipe->so_stats.num_primitives_written;
217       pq->num_primitives_generated = llvmpipe->so_stats.primitives_storage_needed;
218       break;
219    case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
220    case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
221       pq->num_primitives_written = llvmpipe->so_stats.num_primitives_written;
222       pq->num_primitives_generated = llvmpipe->so_stats.primitives_storage_needed;
223       break;
224    case PIPE_QUERY_PIPELINE_STATISTICS:
225       /* reset our cache */
226       if (llvmpipe->active_statistics_queries == 0) {
227          memset(&llvmpipe->pipeline_statistics, 0,
228                 sizeof(llvmpipe->pipeline_statistics));
229       }
230       memcpy(&pq->stats, &llvmpipe->pipeline_statistics, sizeof(pq->stats));
231       llvmpipe->active_statistics_queries++;
232       break;
233    case PIPE_QUERY_OCCLUSION_COUNTER:
234    case PIPE_QUERY_OCCLUSION_PREDICATE:
235    case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
236       llvmpipe->active_occlusion_queries++;
237       llvmpipe->dirty |= LP_NEW_OCCLUSION_QUERY;
238       break;
239    default:
240       break;
241    }
242    return true;
243 }
244 
245 
246 static bool
llvmpipe_end_query(struct pipe_context * pipe,struct pipe_query * q)247 llvmpipe_end_query(struct pipe_context *pipe, struct pipe_query *q)
248 {
249    struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
250    struct llvmpipe_query *pq = llvmpipe_query(q);
251 
252    lp_setup_end_query(llvmpipe->setup, pq);
253 
254    switch (pq->type) {
255 
256    case PIPE_QUERY_PRIMITIVES_EMITTED:
257       pq->num_primitives_written =
258          llvmpipe->so_stats.num_primitives_written - pq->num_primitives_written;
259       break;
260    case PIPE_QUERY_PRIMITIVES_GENERATED:
261       pq->num_primitives_generated =
262          llvmpipe->so_stats.primitives_storage_needed - pq->num_primitives_generated;
263       break;
264    case PIPE_QUERY_SO_STATISTICS:
265       pq->num_primitives_written =
266          llvmpipe->so_stats.num_primitives_written - pq->num_primitives_written;
267       pq->num_primitives_generated =
268          llvmpipe->so_stats.primitives_storage_needed - pq->num_primitives_generated;
269       break;
270    case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
271    case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
272       pq->num_primitives_written =
273          llvmpipe->so_stats.num_primitives_written - pq->num_primitives_written;
274       pq->num_primitives_generated =
275          llvmpipe->so_stats.primitives_storage_needed - pq->num_primitives_generated;
276       break;
277    case PIPE_QUERY_PIPELINE_STATISTICS:
278       pq->stats.ia_vertices =
279          llvmpipe->pipeline_statistics.ia_vertices - pq->stats.ia_vertices;
280       pq->stats.ia_primitives =
281          llvmpipe->pipeline_statistics.ia_primitives - pq->stats.ia_primitives;
282       pq->stats.vs_invocations =
283          llvmpipe->pipeline_statistics.vs_invocations - pq->stats.vs_invocations;
284       pq->stats.gs_invocations =
285          llvmpipe->pipeline_statistics.gs_invocations - pq->stats.gs_invocations;
286       pq->stats.gs_primitives =
287          llvmpipe->pipeline_statistics.gs_primitives - pq->stats.gs_primitives;
288       pq->stats.c_invocations =
289          llvmpipe->pipeline_statistics.c_invocations - pq->stats.c_invocations;
290       pq->stats.c_primitives =
291          llvmpipe->pipeline_statistics.c_primitives - pq->stats.c_primitives;
292       pq->stats.ps_invocations =
293          llvmpipe->pipeline_statistics.ps_invocations - pq->stats.ps_invocations;
294 
295       llvmpipe->active_statistics_queries--;
296       break;
297    case PIPE_QUERY_OCCLUSION_COUNTER:
298    case PIPE_QUERY_OCCLUSION_PREDICATE:
299    case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
300       assert(llvmpipe->active_occlusion_queries);
301       llvmpipe->active_occlusion_queries--;
302       llvmpipe->dirty |= LP_NEW_OCCLUSION_QUERY;
303       break;
304    default:
305       break;
306    }
307 
308    return true;
309 }
310 
311 boolean
llvmpipe_check_render_cond(struct llvmpipe_context * lp)312 llvmpipe_check_render_cond(struct llvmpipe_context *lp)
313 {
314    struct pipe_context *pipe = &lp->pipe;
315    boolean b, wait;
316    uint64_t result;
317 
318    if (!lp->render_cond_query)
319       return TRUE; /* no query predicate, draw normally */
320 
321    wait = (lp->render_cond_mode == PIPE_RENDER_COND_WAIT ||
322            lp->render_cond_mode == PIPE_RENDER_COND_BY_REGION_WAIT);
323 
324    b = pipe->get_query_result(pipe, lp->render_cond_query, wait, (void*)&result);
325    if (b)
326       return ((!result) == lp->render_cond_cond);
327    else
328       return TRUE;
329 }
330 
331 static void
llvmpipe_set_active_query_state(struct pipe_context * pipe,boolean enable)332 llvmpipe_set_active_query_state(struct pipe_context *pipe, boolean enable)
333 {
334 }
335 
llvmpipe_init_query_funcs(struct llvmpipe_context * llvmpipe)336 void llvmpipe_init_query_funcs(struct llvmpipe_context *llvmpipe )
337 {
338    llvmpipe->pipe.create_query = llvmpipe_create_query;
339    llvmpipe->pipe.destroy_query = llvmpipe_destroy_query;
340    llvmpipe->pipe.begin_query = llvmpipe_begin_query;
341    llvmpipe->pipe.end_query = llvmpipe_end_query;
342    llvmpipe->pipe.get_query_result = llvmpipe_get_query_result;
343    llvmpipe->pipe.set_active_query_state = llvmpipe_set_active_query_state;
344 }
345 
346 
347