Home | History | Annotate | Download | only in llvmpipe
      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 
     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 *
     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
     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
     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
    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
    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
    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
    332 llvmpipe_set_active_query_state(struct pipe_context *pipe, boolean enable)
    333 {
    334 }
    335 
    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