Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright © 2008 Intel Corporation
  3.  *
  4.  * Permission is hereby granted, free of charge, to any person obtaining a
  5.  * copy of this software and associated documentation files (the "Software"),
  6.  * to deal in the Software without restriction, including without limitation
  7.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8.  * and/or sell copies of the Software, and to permit persons to whom the
  9.  * Software is furnished to do so, subject to the following conditions:
  10.  *
  11.  * The above copyright notice and this permission notice (including the next
  12.  * paragraph) shall be included in all copies or substantial portions of the
  13.  * Software.
  14.  *
  15.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  18.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20.  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  21.  * IN THE SOFTWARE.
  22.  *
  23.  * Authors:
  24.  *    Eric Anholt <eric@anholt.net>
  25.  *    Kenneth Graunke <kenneth@whitecape.org>
  26.  */
  27.  
  28. /** @file gen6_queryobj.c
  29.  *
  30.  * Support for query objects (GL_ARB_occlusion_query, GL_ARB_timer_query,
  31.  * GL_EXT_transform_feedback, and friends) on platforms that support
  32.  * hardware contexts (Gen6+).
  33.  */
  34. #include "main/imports.h"
  35.  
  36. #include "brw_context.h"
  37. #include "brw_defines.h"
  38. #include "brw_state.h"
  39. #include "intel_batchbuffer.h"
  40. #include "intel_reg.h"
  41.  
  42. /*
  43.  * Write an arbitrary 64-bit register to a buffer via MI_STORE_REGISTER_MEM.
  44.  *
  45.  * Only TIMESTAMP and PS_DEPTH_COUNT have special PIPE_CONTROL support; other
  46.  * counters have to be read via the generic MI_STORE_REGISTER_MEM.
  47.  *
  48.  * Callers must explicitly flush the pipeline to ensure the desired value is
  49.  * available.
  50.  */
  51. void
  52. brw_store_register_mem64(struct brw_context *brw,
  53.                          drm_intel_bo *bo, uint32_t reg, int idx)
  54. {
  55.    assert(brw->gen >= 6);
  56.  
  57.    /* MI_STORE_REGISTER_MEM only stores a single 32-bit value, so to
  58.     * read a full 64-bit register, we need to do two of them.
  59.     */
  60.    if (brw->gen >= 8) {
  61.       BEGIN_BATCH(8);
  62.       OUT_BATCH(MI_STORE_REGISTER_MEM | (4 - 2));
  63.       OUT_BATCH(reg);
  64.       OUT_RELOC64(bo, I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION,
  65.                   idx * sizeof(uint64_t));
  66.       OUT_BATCH(MI_STORE_REGISTER_MEM | (4 - 2));
  67.       OUT_BATCH(reg + sizeof(uint32_t));
  68.       OUT_RELOC64(bo, I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION,
  69.                   sizeof(uint32_t) + idx * sizeof(uint64_t));
  70.       ADVANCE_BATCH();
  71.    } else {
  72.       BEGIN_BATCH(6);
  73.       OUT_BATCH(MI_STORE_REGISTER_MEM | (3 - 2));
  74.       OUT_BATCH(reg);
  75.       OUT_RELOC(bo, I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION,
  76.                 idx * sizeof(uint64_t));
  77.       OUT_BATCH(MI_STORE_REGISTER_MEM | (3 - 2));
  78.       OUT_BATCH(reg + sizeof(uint32_t));
  79.       OUT_RELOC(bo, I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION,
  80.                 sizeof(uint32_t) + idx * sizeof(uint64_t));
  81.       ADVANCE_BATCH();
  82.    }
  83. }
  84.  
  85. static void
  86. write_primitives_generated(struct brw_context *brw,
  87.                            drm_intel_bo *query_bo, int stream, int idx)
  88. {
  89.    intel_batchbuffer_emit_mi_flush(brw);
  90.  
  91.    if (brw->gen >= 7 && stream > 0) {
  92.       brw_store_register_mem64(brw, query_bo,
  93.                                GEN7_SO_PRIM_STORAGE_NEEDED(stream), idx);
  94.    } else {
  95.       brw_store_register_mem64(brw, query_bo, CL_INVOCATION_COUNT, idx);
  96.    }
  97. }
  98.  
  99. static void
  100. write_xfb_primitives_written(struct brw_context *brw,
  101.                              drm_intel_bo *bo, int stream, int idx)
  102. {
  103.    intel_batchbuffer_emit_mi_flush(brw);
  104.  
  105.    if (brw->gen >= 7) {
  106.       brw_store_register_mem64(brw, bo, GEN7_SO_NUM_PRIMS_WRITTEN(stream), idx);
  107.    } else {
  108.       brw_store_register_mem64(brw, bo, GEN6_SO_NUM_PRIMS_WRITTEN, idx);
  109.    }
  110. }
  111.  
  112. static inline const int
  113. pipeline_target_to_index(int target)
  114. {
  115.    if (target == GL_GEOMETRY_SHADER_INVOCATIONS)
  116.       return MAX_PIPELINE_STATISTICS - 1;
  117.    else
  118.       return target - GL_VERTICES_SUBMITTED_ARB;
  119. }
  120.  
  121. static void
  122. emit_pipeline_stat(struct brw_context *brw, drm_intel_bo *bo,
  123.                    int stream, int target, int idx)
  124. {
  125.    /* One source of confusion is the tessellation shader statistics. The
  126.     * hardware has no statistics specific to the TE unit. Ideally we could have
  127.     * the HS primitives for TESS_CONTROL_SHADER_PATCHES_ARB, and the DS
  128.     * invocations as the register for TESS_CONTROL_SHADER_PATCHES_ARB.
  129.     * Unfortunately we don't have HS primitives, we only have HS invocations.
  130.     */
  131.  
  132.    /* Everything except GEOMETRY_SHADER_INVOCATIONS can be kept in a simple
  133.     * lookup table
  134.     */
  135.    static const uint32_t target_to_register[] = {
  136.       IA_VERTICES_COUNT,   /* VERTICES_SUBMITTED */
  137.       IA_PRIMITIVES_COUNT, /* PRIMITIVES_SUBMITTED */
  138.       VS_INVOCATION_COUNT, /* VERTEX_SHADER_INVOCATIONS */
  139.       0, /* HS_INVOCATION_COUNT,*/  /* TESS_CONTROL_SHADER_PATCHES */
  140.       0, /* DS_INVOCATION_COUNT,*/  /* TESS_EVALUATION_SHADER_INVOCATIONS */
  141.       GS_PRIMITIVES_COUNT, /* GEOMETRY_SHADER_PRIMITIVES_EMITTED */
  142.       PS_INVOCATION_COUNT, /* FRAGMENT_SHADER_INVOCATIONS */
  143.       CS_INVOCATION_COUNT, /* COMPUTE_SHADER_INVOCATIONS */
  144.       CL_INVOCATION_COUNT, /* CLIPPING_INPUT_PRIMITIVES */
  145.       CL_PRIMITIVES_COUNT, /* CLIPPING_OUTPUT_PRIMITIVES */
  146.       GS_INVOCATION_COUNT /* This one is special... */
  147.    };
  148.    STATIC_ASSERT(ARRAY_SIZE(target_to_register) == MAX_PIPELINE_STATISTICS);
  149.    uint32_t reg = target_to_register[pipeline_target_to_index(target)];
  150.    /* Gen6 GS code counts full primitives, that is, it won't count individual
  151.     * triangles in a triangle strip. Use CL_INVOCATION_COUNT for that.
  152.     */
  153.    if (brw->gen == 6 && target == GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB)
  154.       reg = CL_INVOCATION_COUNT;
  155.    assert(reg != 0);
  156.  
  157.    /* Emit a flush to make sure various parts of the pipeline are complete and
  158.     * we get an accurate value
  159.     */
  160.    intel_batchbuffer_emit_mi_flush(brw);
  161.  
  162.    brw_store_register_mem64(brw, bo, reg, idx);
  163. }
  164.  
  165.  
  166. /**
  167.  * Wait on the query object's BO and calculate the final result.
  168.  */
  169. static void
  170. gen6_queryobj_get_results(struct gl_context *ctx,
  171.                           struct brw_query_object *query)
  172. {
  173.    struct brw_context *brw = brw_context(ctx);
  174.  
  175.    if (query->bo == NULL)
  176.       return;
  177.  
  178.    brw_bo_map(brw, query->bo, false, "query object");
  179.    uint64_t *results = query->bo->virtual;
  180.    switch (query->Base.Target) {
  181.    case GL_TIME_ELAPSED:
  182.       /* The query BO contains the starting and ending timestamps.
  183.        * Subtract the two and convert to nanoseconds.
  184.        */
  185.       query->Base.Result += 80 * (results[1] - results[0]);
  186.       break;
  187.  
  188.    case GL_TIMESTAMP:
  189.       /* Our timer is a clock that increments every 80ns (regardless of
  190.        * other clock scaling in the system).  The timestamp register we can
  191.        * read for glGetTimestamp() masks out the top 32 bits, so we do that
  192.        * here too to let the two counters be compared against each other.
  193.        *
  194.        * If we just multiplied that 32 bits of data by 80, it would roll
  195.        * over at a non-power-of-two, so an application couldn't use
  196.        * GL_QUERY_COUNTER_BITS to handle rollover correctly.  Instead, we
  197.        * report 36 bits and truncate at that (rolling over 5 times as often
  198.        * as the HW counter), and when the 32-bit counter rolls over, it
  199.        * happens to also be at a rollover in the reported value from near
  200.        * (1<<36) to 0.
  201.        *
  202.        * The low 32 bits rolls over in ~343 seconds.  Our 36-bit result
  203.        * rolls over every ~69 seconds.
  204.        *
  205.        * The query BO contains a single timestamp value in results[0].
  206.        */
  207.       query->Base.Result = 80 * (results[0] & 0xffffffff);
  208.       query->Base.Result &= (1ull << 36) - 1;
  209.       break;
  210.  
  211.    case GL_SAMPLES_PASSED_ARB:
  212.       /* We need to use += rather than = here since some BLT-based operations
  213.        * may have added additional samples to our occlusion query value.
  214.        */
  215.       query->Base.Result += results[1] - results[0];
  216.       break;
  217.  
  218.    case GL_ANY_SAMPLES_PASSED:
  219.    case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
  220.       if (results[0] != results[1])
  221.          query->Base.Result = true;
  222.       break;
  223.  
  224.    case GL_PRIMITIVES_GENERATED:
  225.    case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
  226.    case GL_VERTICES_SUBMITTED_ARB:
  227.    case GL_PRIMITIVES_SUBMITTED_ARB:
  228.    case GL_VERTEX_SHADER_INVOCATIONS_ARB:
  229.    case GL_GEOMETRY_SHADER_INVOCATIONS:
  230.    case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB:
  231.    case GL_CLIPPING_INPUT_PRIMITIVES_ARB:
  232.    case GL_CLIPPING_OUTPUT_PRIMITIVES_ARB:
  233.    case GL_COMPUTE_SHADER_INVOCATIONS_ARB:
  234.       query->Base.Result = results[1] - results[0];
  235.       break;
  236.  
  237.    case GL_FRAGMENT_SHADER_INVOCATIONS_ARB:
  238.       query->Base.Result = (results[1] - results[0]);
  239.       /* Implement the "WaDividePSInvocationCountBy4:HSW,BDW" workaround:
  240.        * "Invocation counter is 4 times actual.  WA: SW to divide HW reported
  241.        *  PS Invocations value by 4."
  242.        *
  243.        * Prior to Haswell, invocation count was counted by the WM, and it
  244.        * buggily counted invocations in units of subspans (2x2 unit). To get the
  245.        * correct value, the CS multiplied this by 4. With HSW the logic moved,
  246.        * and correctly emitted the number of pixel shader invocations, but,
  247.        * whomever forgot to undo the multiply by 4.
  248.        */
  249.       if (brw->gen >= 8 || brw->is_haswell)
  250.          query->Base.Result /= 4;
  251.       break;
  252.  
  253.    case GL_TESS_CONTROL_SHADER_PATCHES_ARB:
  254.    case GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB:
  255.    default:
  256.       unreachable("Unrecognized query target in brw_queryobj_get_results()");
  257.    }
  258.    drm_intel_bo_unmap(query->bo);
  259.  
  260.    /* Now that we've processed the data stored in the query's buffer object,
  261.     * we can release it.
  262.     */
  263.    drm_intel_bo_unreference(query->bo);
  264.    query->bo = NULL;
  265.  
  266.    query->Base.Ready = true;
  267. }
  268.  
  269. /**
  270.  * Driver hook for glBeginQuery().
  271.  *
  272.  * Initializes driver structures and emits any GPU commands required to begin
  273.  * recording data for the query.
  274.  */
  275. static void
  276. gen6_begin_query(struct gl_context *ctx, struct gl_query_object *q)
  277. {
  278.    struct brw_context *brw = brw_context(ctx);
  279.    struct brw_query_object *query = (struct brw_query_object *)q;
  280.  
  281.    /* Since we're starting a new query, we need to throw away old results. */
  282.    drm_intel_bo_unreference(query->bo);
  283.    query->bo = drm_intel_bo_alloc(brw->bufmgr, "query results", 4096, 4096);
  284.  
  285.    switch (query->Base.Target) {
  286.    case GL_TIME_ELAPSED:
  287.       /* For timestamp queries, we record the starting time right away so that
  288.        * we measure the full time between BeginQuery and EndQuery.  There's
  289.        * some debate about whether this is the right thing to do.  Our decision
  290.        * is based on the following text from the ARB_timer_query extension:
  291.        *
  292.        * "(5) Should the extension measure total time elapsed between the full
  293.        *      completion of the BeginQuery and EndQuery commands, or just time
  294.        *      spent in the graphics library?
  295.        *
  296.        *  RESOLVED:  This extension will measure the total time elapsed
  297.        *  between the full completion of these commands.  Future extensions
  298.        *  may implement a query to determine time elapsed at different stages
  299.        *  of the graphics pipeline."
  300.        *
  301.        * We write a starting timestamp now (at index 0).  At EndQuery() time,
  302.        * we'll write a second timestamp (at index 1), and subtract the two to
  303.        * obtain the time elapsed.  Notably, this includes time elapsed while
  304.        * the system was doing other work, such as running other applications.
  305.        */
  306.       brw_write_timestamp(brw, query->bo, 0);
  307.       break;
  308.  
  309.    case GL_ANY_SAMPLES_PASSED:
  310.    case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
  311.    case GL_SAMPLES_PASSED_ARB:
  312.       brw_write_depth_count(brw, query->bo, 0);
  313.       break;
  314.  
  315.    case GL_PRIMITIVES_GENERATED:
  316.       write_primitives_generated(brw, query->bo, query->Base.Stream, 0);
  317.       break;
  318.  
  319.    case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
  320.       write_xfb_primitives_written(brw, query->bo, query->Base.Stream, 0);
  321.       break;
  322.  
  323.    case GL_VERTICES_SUBMITTED_ARB:
  324.    case GL_PRIMITIVES_SUBMITTED_ARB:
  325.    case GL_VERTEX_SHADER_INVOCATIONS_ARB:
  326.    case GL_GEOMETRY_SHADER_INVOCATIONS:
  327.    case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB:
  328.    case GL_FRAGMENT_SHADER_INVOCATIONS_ARB:
  329.    case GL_CLIPPING_INPUT_PRIMITIVES_ARB:
  330.    case GL_CLIPPING_OUTPUT_PRIMITIVES_ARB:
  331.    case GL_COMPUTE_SHADER_INVOCATIONS_ARB:
  332.       emit_pipeline_stat(brw, query->bo, query->Base.Stream, query->Base.Target, 0);
  333.       break;
  334.  
  335.    case GL_TESS_CONTROL_SHADER_PATCHES_ARB:
  336.    case GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB:
  337.    default:
  338.       unreachable("Unrecognized query target in brw_begin_query()");
  339.    }
  340. }
  341.  
  342. /**
  343.  * Driver hook for glEndQuery().
  344.  *
  345.  * Emits GPU commands to record a final query value, ending any data capturing.
  346.  * However, the final result isn't necessarily available until the GPU processes
  347.  * those commands.  brw_queryobj_get_results() processes the captured data to
  348.  * produce the final result.
  349.  */
  350. static void
  351. gen6_end_query(struct gl_context *ctx, struct gl_query_object *q)
  352. {
  353.    struct brw_context *brw = brw_context(ctx);
  354.    struct brw_query_object *query = (struct brw_query_object *)q;
  355.  
  356.    switch (query->Base.Target) {
  357.    case GL_TIME_ELAPSED:
  358.       brw_write_timestamp(brw, query->bo, 1);
  359.       break;
  360.  
  361.    case GL_ANY_SAMPLES_PASSED:
  362.    case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
  363.    case GL_SAMPLES_PASSED_ARB:
  364.       brw_write_depth_count(brw, query->bo, 1);
  365.       break;
  366.  
  367.    case GL_PRIMITIVES_GENERATED:
  368.       write_primitives_generated(brw, query->bo, query->Base.Stream, 1);
  369.       break;
  370.  
  371.    case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
  372.       write_xfb_primitives_written(brw, query->bo, query->Base.Stream, 1);
  373.       break;
  374.  
  375.    case GL_VERTICES_SUBMITTED_ARB:
  376.    case GL_PRIMITIVES_SUBMITTED_ARB:
  377.    case GL_VERTEX_SHADER_INVOCATIONS_ARB:
  378.    case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB:
  379.    case GL_FRAGMENT_SHADER_INVOCATIONS_ARB:
  380.    case GL_COMPUTE_SHADER_INVOCATIONS_ARB:
  381.    case GL_CLIPPING_INPUT_PRIMITIVES_ARB:
  382.    case GL_CLIPPING_OUTPUT_PRIMITIVES_ARB:
  383.    case GL_GEOMETRY_SHADER_INVOCATIONS:
  384.       emit_pipeline_stat(brw, query->bo,
  385.                          query->Base.Stream, query->Base.Target, 1);
  386.       break;
  387.  
  388.    case GL_TESS_CONTROL_SHADER_PATCHES_ARB:
  389.    case GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB:
  390.    default:
  391.       unreachable("Unrecognized query target in brw_end_query()");
  392.    }
  393.  
  394.    /* The current batch contains the commands to handle EndQuery(),
  395.     * but they won't actually execute until it is flushed.
  396.     */
  397.    query->flushed = false;
  398. }
  399.  
  400. /**
  401.  * Flush the batch if it still references the query object BO.
  402.  */
  403. static void
  404. flush_batch_if_needed(struct brw_context *brw, struct brw_query_object *query)
  405. {
  406.    /* If the batch doesn't reference the BO, it must have been flushed
  407.     * (for example, due to being full).  Record that it's been flushed.
  408.     */
  409.    query->flushed = query->flushed ||
  410.       !drm_intel_bo_references(brw->batch.bo, query->bo);
  411.  
  412.    if (!query->flushed)
  413.       intel_batchbuffer_flush(brw);
  414. }
  415.  
  416. /**
  417.  * The WaitQuery() driver hook.
  418.  *
  419.  * Wait for a query result to become available and return it.  This is the
  420.  * backing for glGetQueryObjectiv() with the GL_QUERY_RESULT pname.
  421.  */
  422. static void gen6_wait_query(struct gl_context *ctx, struct gl_query_object *q)
  423. {
  424.    struct brw_context *brw = brw_context(ctx);
  425.    struct brw_query_object *query = (struct brw_query_object *)q;
  426.  
  427.    /* If the application has requested the query result, but this batch is
  428.     * still contributing to it, flush it now to finish that work so the
  429.     * result will become available (eventually).
  430.     */
  431.    flush_batch_if_needed(brw, query);
  432.  
  433.    gen6_queryobj_get_results(ctx, query);
  434. }
  435.  
  436. /**
  437.  * The CheckQuery() driver hook.
  438.  *
  439.  * Checks whether a query result is ready yet.  If not, flushes.
  440.  * This is the backing for glGetQueryObjectiv()'s QUERY_RESULT_AVAILABLE pname.
  441.  */
  442. static void gen6_check_query(struct gl_context *ctx, struct gl_query_object *q)
  443. {
  444.    struct brw_context *brw = brw_context(ctx);
  445.    struct brw_query_object *query = (struct brw_query_object *)q;
  446.  
  447.    /* If query->bo is NULL, we've already gathered the results - this is a
  448.     * redundant CheckQuery call.  Ignore it.
  449.     */
  450.    if (query->bo == NULL)
  451.       return;
  452.  
  453.    /* From the GL_ARB_occlusion_query spec:
  454.     *
  455.     *     "Instead of allowing for an infinite loop, performing a
  456.     *      QUERY_RESULT_AVAILABLE_ARB will perform a flush if the result is
  457.     *      not ready yet on the first time it is queried.  This ensures that
  458.     *      the async query will return true in finite time.
  459.     */
  460.    flush_batch_if_needed(brw, query);
  461.  
  462.    if (!drm_intel_bo_busy(query->bo)) {
  463.       gen6_queryobj_get_results(ctx, query);
  464.    }
  465. }
  466.  
  467. /* Initialize Gen6+-specific query object functions. */
  468. void gen6_init_queryobj_functions(struct dd_function_table *functions)
  469. {
  470.    functions->BeginQuery = gen6_begin_query;
  471.    functions->EndQuery = gen6_end_query;
  472.    functions->CheckQuery = gen6_check_query;
  473.    functions->WaitQuery = gen6_wait_query;
  474. }
  475.