• 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 "os/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       for (i = 0; i < num_threads; i++) {
129          /* safer (still not guaranteed) when there's an overflow */
130          vresult->b = vresult->b || pq->end[i];
131       }
132       break;
133    case PIPE_QUERY_TIMESTAMP:
134       for (i = 0; i < num_threads; i++) {
135          if (pq->end[i] > *result) {
136             *result = pq->end[i];
137          }
138       }
139       break;
140    case PIPE_QUERY_TIMESTAMP_DISJOINT: {
141       struct pipe_query_data_timestamp_disjoint *td =
142          (struct pipe_query_data_timestamp_disjoint *)vresult;
143       /* os_get_time_nano return nanoseconds */
144       td->frequency = UINT64_C(1000000000);
145       td->disjoint = FALSE;
146    }
147       break;
148    case PIPE_QUERY_GPU_FINISHED:
149       vresult->b = TRUE;
150       break;
151    case PIPE_QUERY_PRIMITIVES_GENERATED:
152       *result = pq->num_primitives_generated;
153       break;
154    case PIPE_QUERY_PRIMITIVES_EMITTED:
155       *result = pq->num_primitives_written;
156       break;
157    case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
158       vresult->b = pq->num_primitives_generated > pq->num_primitives_written;
159       break;
160    case PIPE_QUERY_SO_STATISTICS: {
161       struct pipe_query_data_so_statistics *stats =
162          (struct pipe_query_data_so_statistics *)vresult;
163       stats->num_primitives_written = pq->num_primitives_written;
164       stats->primitives_storage_needed = pq->num_primitives_generated;
165    }
166       break;
167    case PIPE_QUERY_PIPELINE_STATISTICS: {
168       struct pipe_query_data_pipeline_statistics *stats =
169          (struct pipe_query_data_pipeline_statistics *)vresult;
170       /* only ps_invocations come from binned query */
171       for (i = 0; i < num_threads; i++) {
172          pq->stats.ps_invocations += pq->end[i];
173       }
174       pq->stats.ps_invocations *= LP_RASTER_BLOCK_SIZE * LP_RASTER_BLOCK_SIZE;
175       *stats = pq->stats;
176    }
177       break;
178    default:
179       assert(0);
180       break;
181    }
182 
183    return TRUE;
184 }
185 
186 
187 static boolean
llvmpipe_begin_query(struct pipe_context * pipe,struct pipe_query * q)188 llvmpipe_begin_query(struct pipe_context *pipe, struct pipe_query *q)
189 {
190    struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
191    struct llvmpipe_query *pq = llvmpipe_query(q);
192 
193    /* Check if the query is already in the scene.  If so, we need to
194     * flush the scene now.  Real apps shouldn't re-use a query in a
195     * frame of rendering.
196     */
197    if (pq->fence && !lp_fence_issued(pq->fence)) {
198       llvmpipe_finish(pipe, __FUNCTION__);
199    }
200 
201 
202    memset(pq->start, 0, sizeof(pq->start));
203    memset(pq->end, 0, sizeof(pq->end));
204    lp_setup_begin_query(llvmpipe->setup, pq);
205 
206    switch (pq->type) {
207    case PIPE_QUERY_PRIMITIVES_EMITTED:
208       pq->num_primitives_written = llvmpipe->so_stats.num_primitives_written;
209       break;
210    case PIPE_QUERY_PRIMITIVES_GENERATED:
211       pq->num_primitives_generated = llvmpipe->so_stats.primitives_storage_needed;
212       break;
213    case PIPE_QUERY_SO_STATISTICS:
214       pq->num_primitives_written = llvmpipe->so_stats.num_primitives_written;
215       pq->num_primitives_generated = llvmpipe->so_stats.primitives_storage_needed;
216       break;
217    case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
218       pq->num_primitives_written = llvmpipe->so_stats.num_primitives_written;
219       pq->num_primitives_generated = llvmpipe->so_stats.primitives_storage_needed;
220       break;
221    case PIPE_QUERY_PIPELINE_STATISTICS:
222       /* reset our cache */
223       if (llvmpipe->active_statistics_queries == 0) {
224          memset(&llvmpipe->pipeline_statistics, 0,
225                 sizeof(llvmpipe->pipeline_statistics));
226       }
227       memcpy(&pq->stats, &llvmpipe->pipeline_statistics, sizeof(pq->stats));
228       llvmpipe->active_statistics_queries++;
229       break;
230    case PIPE_QUERY_OCCLUSION_COUNTER:
231    case PIPE_QUERY_OCCLUSION_PREDICATE:
232       llvmpipe->active_occlusion_queries++;
233       llvmpipe->dirty |= LP_NEW_OCCLUSION_QUERY;
234       break;
235    default:
236       break;
237    }
238    return true;
239 }
240 
241 
242 static bool
llvmpipe_end_query(struct pipe_context * pipe,struct pipe_query * q)243 llvmpipe_end_query(struct pipe_context *pipe, struct pipe_query *q)
244 {
245    struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
246    struct llvmpipe_query *pq = llvmpipe_query(q);
247 
248    lp_setup_end_query(llvmpipe->setup, pq);
249 
250    switch (pq->type) {
251 
252    case PIPE_QUERY_PRIMITIVES_EMITTED:
253       pq->num_primitives_written =
254          llvmpipe->so_stats.num_primitives_written - pq->num_primitives_written;
255       break;
256    case PIPE_QUERY_PRIMITIVES_GENERATED:
257       pq->num_primitives_generated =
258          llvmpipe->so_stats.primitives_storage_needed - pq->num_primitives_generated;
259       break;
260    case PIPE_QUERY_SO_STATISTICS:
261       pq->num_primitives_written =
262          llvmpipe->so_stats.num_primitives_written - pq->num_primitives_written;
263       pq->num_primitives_generated =
264          llvmpipe->so_stats.primitives_storage_needed - pq->num_primitives_generated;
265       break;
266    case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
267       pq->num_primitives_written =
268          llvmpipe->so_stats.num_primitives_written - pq->num_primitives_written;
269       pq->num_primitives_generated =
270          llvmpipe->so_stats.primitives_storage_needed - pq->num_primitives_generated;
271       break;
272    case PIPE_QUERY_PIPELINE_STATISTICS:
273       pq->stats.ia_vertices =
274          llvmpipe->pipeline_statistics.ia_vertices - pq->stats.ia_vertices;
275       pq->stats.ia_primitives =
276          llvmpipe->pipeline_statistics.ia_primitives - pq->stats.ia_primitives;
277       pq->stats.vs_invocations =
278          llvmpipe->pipeline_statistics.vs_invocations - pq->stats.vs_invocations;
279       pq->stats.gs_invocations =
280          llvmpipe->pipeline_statistics.gs_invocations - pq->stats.gs_invocations;
281       pq->stats.gs_primitives =
282          llvmpipe->pipeline_statistics.gs_primitives - pq->stats.gs_primitives;
283       pq->stats.c_invocations =
284          llvmpipe->pipeline_statistics.c_invocations - pq->stats.c_invocations;
285       pq->stats.c_primitives =
286          llvmpipe->pipeline_statistics.c_primitives - pq->stats.c_primitives;
287       pq->stats.ps_invocations =
288          llvmpipe->pipeline_statistics.ps_invocations - pq->stats.ps_invocations;
289 
290       llvmpipe->active_statistics_queries--;
291       break;
292    case PIPE_QUERY_OCCLUSION_COUNTER:
293    case PIPE_QUERY_OCCLUSION_PREDICATE:
294       assert(llvmpipe->active_occlusion_queries);
295       llvmpipe->active_occlusion_queries--;
296       llvmpipe->dirty |= LP_NEW_OCCLUSION_QUERY;
297       break;
298    default:
299       break;
300    }
301 
302    return true;
303 }
304 
305 boolean
llvmpipe_check_render_cond(struct llvmpipe_context * lp)306 llvmpipe_check_render_cond(struct llvmpipe_context *lp)
307 {
308    struct pipe_context *pipe = &lp->pipe;
309    boolean b, wait;
310    uint64_t result;
311 
312    if (!lp->render_cond_query)
313       return TRUE; /* no query predicate, draw normally */
314 
315    wait = (lp->render_cond_mode == PIPE_RENDER_COND_WAIT ||
316            lp->render_cond_mode == PIPE_RENDER_COND_BY_REGION_WAIT);
317 
318    b = pipe->get_query_result(pipe, lp->render_cond_query, wait, (void*)&result);
319    if (b)
320       return ((!result) == lp->render_cond_cond);
321    else
322       return TRUE;
323 }
324 
325 static void
llvmpipe_set_active_query_state(struct pipe_context * pipe,boolean enable)326 llvmpipe_set_active_query_state(struct pipe_context *pipe, boolean enable)
327 {
328 }
329 
llvmpipe_init_query_funcs(struct llvmpipe_context * llvmpipe)330 void llvmpipe_init_query_funcs(struct llvmpipe_context *llvmpipe )
331 {
332    llvmpipe->pipe.create_query = llvmpipe_create_query;
333    llvmpipe->pipe.destroy_query = llvmpipe_destroy_query;
334    llvmpipe->pipe.begin_query = llvmpipe_begin_query;
335    llvmpipe->pipe.end_query = llvmpipe_end_query;
336    llvmpipe->pipe.get_query_result = llvmpipe_get_query_result;
337    llvmpipe->pipe.set_active_query_state = llvmpipe_set_active_query_state;
338 }
339 
340 
341