Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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.  
  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.       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
  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 void
  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.  
  303. boolean
  304. llvmpipe_check_render_cond(struct llvmpipe_context *lp)
  305. {
  306.    struct pipe_context *pipe = &lp->pipe;
  307.    boolean b, wait;
  308.    uint64_t result;
  309.  
  310.    if (!lp->render_cond_query)
  311.       return TRUE; /* no query predicate, draw normally */
  312.  
  313.    wait = (lp->render_cond_mode == PIPE_RENDER_COND_WAIT ||
  314.            lp->render_cond_mode == PIPE_RENDER_COND_BY_REGION_WAIT);
  315.  
  316.    b = pipe->get_query_result(pipe, lp->render_cond_query, wait, (void*)&result);
  317.    if (b)
  318.       return ((!result) == lp->render_cond_cond);
  319.    else
  320.       return TRUE;
  321. }
  322.  
  323. void llvmpipe_init_query_funcs(struct llvmpipe_context *llvmpipe )
  324. {
  325.    llvmpipe->pipe.create_query = llvmpipe_create_query;
  326.    llvmpipe->pipe.destroy_query = llvmpipe_destroy_query;
  327.    llvmpipe->pipe.begin_query = llvmpipe_begin_query;
  328.    llvmpipe->pipe.end_query = llvmpipe_end_query;
  329.    llvmpipe->pipe.get_query_result = llvmpipe_get_query_result;
  330. }
  331.  
  332.  
  333.