Home | History | Annotate | Download | only in ilo
      1 /*
      2  * Mesa 3-D graphics library
      3  *
      4  * Copyright (C) 2013 LunarG, Inc.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included
     14  * in all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     22  * DEALINGS IN THE SOFTWARE.
     23  *
     24  * Authors:
     25  *    Chia-I Wu <olv (at) lunarg.com>
     26  */
     27 
     28 #include "genhw/genhw.h"
     29 #include "core/ilo_builder.h"
     30 #include "core/ilo_builder_mi.h"
     31 #include "core/ilo_builder_render.h"
     32 #include "core/intel_winsys.h"
     33 #include "util/u_prim.h"
     34 
     35 #include "ilo_query.h"
     36 #include "ilo_render_gen.h"
     37 
     38 struct ilo_render *
     39 ilo_render_create(struct ilo_builder *builder)
     40 {
     41    struct ilo_render *render;
     42 
     43    render = CALLOC_STRUCT(ilo_render);
     44    if (!render)
     45       return NULL;
     46 
     47    render->dev = builder->dev;
     48    render->builder = builder;
     49 
     50    render->workaround_bo = intel_winsys_alloc_bo(builder->winsys,
     51          "PIPE_CONTROL workaround", 4096, false);
     52    if (!render->workaround_bo) {
     53       ilo_warn("failed to allocate PIPE_CONTROL workaround bo\n");
     54       FREE(render);
     55       return NULL;
     56    }
     57 
     58    ilo_state_sample_pattern_init_default(&render->sample_pattern,
     59          render->dev);
     60 
     61    ilo_render_invalidate_hw(render);
     62    ilo_render_invalidate_builder(render);
     63 
     64    return render;
     65 }
     66 
     67 void
     68 ilo_render_destroy(struct ilo_render *render)
     69 {
     70    intel_bo_unref(render->vs_scratch.bo);
     71    intel_bo_unref(render->gs_scratch.bo);
     72    intel_bo_unref(render->fs_scratch.bo);
     73 
     74    intel_bo_unref(render->workaround_bo);
     75    FREE(render);
     76 }
     77 
     78 static bool
     79 resize_scratch_space(struct ilo_render *render,
     80                      struct ilo_render_scratch_space *scratch,
     81                      const char *name, int new_size)
     82 {
     83    struct intel_bo *bo;
     84 
     85    if (scratch->size >= new_size)
     86       return true;
     87 
     88    bo = intel_winsys_alloc_bo(render->builder->winsys, name, new_size, false);
     89    if (!bo)
     90       return false;
     91 
     92    intel_bo_unref(scratch->bo);
     93    scratch->bo = bo;
     94    scratch->size = new_size;
     95 
     96    return true;
     97 }
     98 
     99 bool
    100 ilo_render_prepare_scratch_spaces(struct ilo_render *render,
    101                                   int vs_scratch_size,
    102                                   int gs_scratch_size,
    103                                   int fs_scratch_size)
    104 {
    105    return (resize_scratch_space(render, &render->vs_scratch,
    106             "vs scratch", vs_scratch_size) &&
    107            resize_scratch_space(render, &render->gs_scratch,
    108             "gs scratch", gs_scratch_size) &&
    109            resize_scratch_space(render, &render->fs_scratch,
    110             "fs scratch", fs_scratch_size));
    111 }
    112 
    113 void
    114 ilo_render_get_sample_position(const struct ilo_render *render,
    115                                unsigned sample_count,
    116                                unsigned sample_index,
    117                                float *x, float *y)
    118 {
    119    uint8_t off_x, off_y;
    120 
    121    ilo_state_sample_pattern_get_offset(&render->sample_pattern, render->dev,
    122          sample_count, sample_index, &off_x, &off_y);
    123 
    124    *x = (float) off_x / 16.0f;
    125    *y = (float) off_y / 16.0f;
    126 }
    127 
    128 void
    129 ilo_render_invalidate_hw(struct ilo_render *render)
    130 {
    131    render->hw_ctx_changed = true;
    132 }
    133 
    134 void
    135 ilo_render_invalidate_builder(struct ilo_render *render)
    136 {
    137    render->batch_bo_changed = true;
    138    render->state_bo_changed = true;
    139    render->instruction_bo_changed = true;
    140 
    141    /* Kernel flushes everything.  Shouldn't we set all bits here? */
    142    render->state.current_pipe_control_dw1 = 0;
    143 }
    144 
    145 /**
    146  * Return the command length of ilo_render_emit_flush().
    147  */
    148 int
    149 ilo_render_get_flush_len(const struct ilo_render *render)
    150 {
    151    int len;
    152 
    153    ILO_DEV_ASSERT(render->dev, 6, 8);
    154 
    155    len = GEN6_PIPE_CONTROL__SIZE;
    156 
    157    /* plus gen6_wa_pre_pipe_control() */
    158    if (ilo_dev_gen(render->dev) == ILO_GEN(6))
    159       len *= 3;
    160 
    161    return len;
    162 }
    163 
    164 /**
    165  * Emit PIPE_CONTROLs to flush all caches.
    166  */
    167 void
    168 ilo_render_emit_flush(struct ilo_render *render)
    169 {
    170    const uint32_t dw1 = GEN6_PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE |
    171                         GEN6_PIPE_CONTROL_RENDER_CACHE_FLUSH |
    172                         GEN6_PIPE_CONTROL_DEPTH_CACHE_FLUSH |
    173                         GEN6_PIPE_CONTROL_VF_CACHE_INVALIDATE |
    174                         GEN6_PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE |
    175                         GEN6_PIPE_CONTROL_CS_STALL;
    176    const unsigned batch_used = ilo_builder_batch_used(render->builder);
    177 
    178    ILO_DEV_ASSERT(render->dev, 6, 8);
    179 
    180    if (ilo_dev_gen(render->dev) == ILO_GEN(6))
    181       gen6_wa_pre_pipe_control(render, dw1);
    182 
    183    ilo_render_pipe_control(render, dw1);
    184 
    185    assert(ilo_builder_batch_used(render->builder) <= batch_used +
    186          ilo_render_get_flush_len(render));
    187 }
    188 
    189 /**
    190  * Return the command length of ilo_render_emit_query().
    191  */
    192 int
    193 ilo_render_get_query_len(const struct ilo_render *render,
    194                          unsigned query_type)
    195 {
    196    int len;
    197 
    198    ILO_DEV_ASSERT(render->dev, 6, 8);
    199 
    200    /* always a flush or a variant of flush */
    201    len = ilo_render_get_flush_len(render);
    202 
    203    switch (query_type) {
    204    case PIPE_QUERY_OCCLUSION_COUNTER:
    205    case PIPE_QUERY_OCCLUSION_PREDICATE:
    206    case PIPE_QUERY_TIMESTAMP:
    207    case PIPE_QUERY_TIME_ELAPSED:
    208       /* no reg */
    209       break;
    210    case PIPE_QUERY_PRIMITIVES_GENERATED:
    211    case PIPE_QUERY_PRIMITIVES_EMITTED:
    212       len += GEN6_MI_STORE_REGISTER_MEM__SIZE * 2;
    213       break;
    214    case PIPE_QUERY_PIPELINE_STATISTICS:
    215       {
    216          const int num_regs =
    217             (ilo_dev_gen(render->dev) >= ILO_GEN(7)) ? 10 : 8;
    218          const int num_pads =
    219             (ilo_dev_gen(render->dev) >= ILO_GEN(7)) ? 1 : 3;
    220 
    221          len += GEN6_MI_STORE_REGISTER_MEM__SIZE * 2 * num_regs +
    222                 GEN6_MI_STORE_DATA_IMM__SIZE * num_pads;
    223       }
    224       break;
    225    default:
    226       len = 0;
    227       break;
    228    }
    229 
    230    return len;
    231 }
    232 
    233 /**
    234  * Emit PIPE_CONTROLs or MI_STORE_REGISTER_MEMs to store register values.
    235  */
    236 void
    237 ilo_render_emit_query(struct ilo_render *render,
    238                       struct ilo_query *q, uint32_t offset)
    239 {
    240    const uint32_t pipeline_statistics_regs[11] = {
    241       GEN6_REG_IA_VERTICES_COUNT,
    242       GEN6_REG_IA_PRIMITIVES_COUNT,
    243       GEN6_REG_VS_INVOCATION_COUNT,
    244       GEN6_REG_GS_INVOCATION_COUNT,
    245       GEN6_REG_GS_PRIMITIVES_COUNT,
    246       GEN6_REG_CL_INVOCATION_COUNT,
    247       GEN6_REG_CL_PRIMITIVES_COUNT,
    248       GEN6_REG_PS_INVOCATION_COUNT,
    249       (ilo_dev_gen(render->dev) >= ILO_GEN(7)) ?
    250          GEN7_REG_HS_INVOCATION_COUNT : 0,
    251       (ilo_dev_gen(render->dev) >= ILO_GEN(7)) ?
    252          GEN7_REG_DS_INVOCATION_COUNT : 0,
    253       0,
    254    };
    255    const uint32_t primitives_generated_reg =
    256       (ilo_dev_gen(render->dev) >= ILO_GEN(7) && q->index > 0) ?
    257       GEN7_REG_SO_PRIM_STORAGE_NEEDED(q->index) :
    258       GEN6_REG_CL_INVOCATION_COUNT;
    259    const uint32_t primitives_emitted_reg =
    260       (ilo_dev_gen(render->dev) >= ILO_GEN(7)) ?
    261       GEN7_REG_SO_NUM_PRIMS_WRITTEN(q->index) :
    262       GEN6_REG_SO_NUM_PRIMS_WRITTEN;
    263    const unsigned batch_used = ilo_builder_batch_used(render->builder);
    264    const uint32_t *regs;
    265    int reg_count = 0, i;
    266    uint32_t pipe_control_dw1 = 0;
    267 
    268    ILO_DEV_ASSERT(render->dev, 6, 8);
    269 
    270    switch (q->type) {
    271    case PIPE_QUERY_OCCLUSION_COUNTER:
    272    case PIPE_QUERY_OCCLUSION_PREDICATE:
    273       pipe_control_dw1 = GEN6_PIPE_CONTROL_DEPTH_STALL |
    274                          GEN6_PIPE_CONTROL_WRITE_PS_DEPTH_COUNT;
    275       break;
    276    case PIPE_QUERY_TIMESTAMP:
    277    case PIPE_QUERY_TIME_ELAPSED:
    278       pipe_control_dw1 = GEN6_PIPE_CONTROL_WRITE_TIMESTAMP;
    279       break;
    280    case PIPE_QUERY_PRIMITIVES_GENERATED:
    281       regs = &primitives_generated_reg;
    282       reg_count = 1;
    283       break;
    284    case PIPE_QUERY_PRIMITIVES_EMITTED:
    285       regs = &primitives_emitted_reg;
    286       reg_count = 1;
    287       break;
    288    case PIPE_QUERY_PIPELINE_STATISTICS:
    289       regs = pipeline_statistics_regs;
    290       reg_count = ARRAY_SIZE(pipeline_statistics_regs);
    291       break;
    292    default:
    293       break;
    294    }
    295 
    296    if (pipe_control_dw1) {
    297       assert(!reg_count);
    298 
    299       if (ilo_dev_gen(render->dev) == ILO_GEN(6))
    300          gen6_wa_pre_pipe_control(render, pipe_control_dw1);
    301 
    302       gen6_PIPE_CONTROL(render->builder, pipe_control_dw1, q->bo, offset, 0);
    303 
    304       render->state.current_pipe_control_dw1 |= pipe_control_dw1;
    305       render->state.deferred_pipe_control_dw1 &= ~pipe_control_dw1;
    306    } else if (reg_count) {
    307       ilo_render_emit_flush(render);
    308    }
    309 
    310    for (i = 0; i < reg_count; i++) {
    311       if (regs[i]) {
    312          /* store lower 32 bits */
    313          gen6_MI_STORE_REGISTER_MEM(render->builder, regs[i], q->bo, offset);
    314          /* store higher 32 bits */
    315          gen6_MI_STORE_REGISTER_MEM(render->builder, regs[i] + 4,
    316                q->bo, offset + 4);
    317       } else {
    318          gen6_MI_STORE_DATA_IMM(render->builder, q->bo, offset, 0);
    319       }
    320 
    321       offset += 8;
    322    }
    323 
    324    assert(ilo_builder_batch_used(render->builder) <= batch_used +
    325          ilo_render_get_query_len(render, q->type));
    326 }
    327 
    328 int
    329 ilo_render_get_rectlist_len(const struct ilo_render *render,
    330                             const struct ilo_blitter *blitter)
    331 {
    332    ILO_DEV_ASSERT(render->dev, 6, 8);
    333 
    334    return ilo_render_get_rectlist_dynamic_states_len(render, blitter) +
    335           ilo_render_get_rectlist_commands_len(render, blitter);
    336 }
    337 
    338 void
    339 ilo_render_emit_rectlist(struct ilo_render *render,
    340                          const struct ilo_blitter *blitter)
    341 {
    342    struct ilo_render_rectlist_session session;
    343 
    344    ILO_DEV_ASSERT(render->dev, 6, 8);
    345 
    346    memset(&session, 0, sizeof(session));
    347    ilo_render_emit_rectlist_dynamic_states(render, blitter, &session);
    348    ilo_render_emit_rectlist_commands(render, blitter, &session);
    349 }
    350 
    351 int
    352 ilo_render_get_draw_len(const struct ilo_render *render,
    353                         const struct ilo_state_vector *vec)
    354 {
    355    ILO_DEV_ASSERT(render->dev, 6, 8);
    356 
    357    return ilo_render_get_draw_dynamic_states_len(render, vec) +
    358           ilo_render_get_draw_surface_states_len(render, vec) +
    359           ilo_render_get_draw_commands_len(render, vec);
    360 }
    361 
    362 static void
    363 draw_session_prepare(struct ilo_render *render,
    364                      const struct ilo_state_vector *vec,
    365                      struct ilo_render_draw_session *session)
    366 {
    367    memset(session, 0, sizeof(*session));
    368    session->pipe_dirty = vec->dirty;
    369    session->reduced_prim = u_reduced_prim(vec->draw->mode);
    370 
    371    if (render->hw_ctx_changed) {
    372       /* these should be enough to make everything uploaded */
    373       render->batch_bo_changed = true;
    374       render->state_bo_changed = true;
    375       render->instruction_bo_changed = true;
    376 
    377       session->prim_changed = true;
    378 
    379       ilo_state_urb_full_delta(&vec->urb, render->dev, &session->urb_delta);
    380       ilo_state_vf_full_delta(&vec->ve->vf, render->dev, &session->vf_delta);
    381 
    382       ilo_state_raster_full_delta(&vec->rasterizer->rs, render->dev,
    383             &session->rs_delta);
    384 
    385       ilo_state_viewport_full_delta(&vec->viewport.vp, render->dev,
    386             &session->vp_delta);
    387 
    388       ilo_state_cc_full_delta(&vec->blend->cc, render->dev,
    389             &session->cc_delta);
    390    } else {
    391       session->prim_changed =
    392          (render->state.reduced_prim != session->reduced_prim);
    393 
    394       ilo_state_urb_get_delta(&vec->urb, render->dev,
    395             &render->state.urb, &session->urb_delta);
    396 
    397       if (vec->dirty & ILO_DIRTY_VE) {
    398          ilo_state_vf_full_delta(&vec->ve->vf, render->dev,
    399                &session->vf_delta);
    400       }
    401 
    402       if (vec->dirty & ILO_DIRTY_RASTERIZER) {
    403          ilo_state_raster_get_delta(&vec->rasterizer->rs, render->dev,
    404                &render->state.rs, &session->rs_delta);
    405       }
    406 
    407       if (vec->dirty & ILO_DIRTY_VIEWPORT) {
    408          ilo_state_viewport_full_delta(&vec->viewport.vp, render->dev,
    409                &session->vp_delta);
    410       }
    411 
    412       if (vec->dirty & ILO_DIRTY_BLEND) {
    413          ilo_state_cc_get_delta(&vec->blend->cc, render->dev,
    414                &render->state.cc, &session->cc_delta);
    415       }
    416    }
    417 }
    418 
    419 static void
    420 draw_session_end(struct ilo_render *render,
    421                  const struct ilo_state_vector *vec,
    422                  struct ilo_render_draw_session *session)
    423 {
    424    render->hw_ctx_changed = false;
    425 
    426    render->batch_bo_changed = false;
    427    render->state_bo_changed = false;
    428    render->instruction_bo_changed = false;
    429 
    430    render->state.reduced_prim = session->reduced_prim;
    431 
    432    render->state.urb = vec->urb;
    433    render->state.rs = vec->rasterizer->rs;
    434    render->state.cc = vec->blend->cc;
    435 }
    436 
    437 void
    438 ilo_render_emit_draw(struct ilo_render *render,
    439                      const struct ilo_state_vector *vec)
    440 {
    441    struct ilo_render_draw_session session;
    442 
    443    ILO_DEV_ASSERT(render->dev, 6, 8);
    444 
    445    draw_session_prepare(render, vec, &session);
    446 
    447    /* force all states to be uploaded if the state bo changed */
    448    if (render->state_bo_changed)
    449       session.pipe_dirty = ILO_DIRTY_ALL;
    450    else
    451       session.pipe_dirty = vec->dirty;
    452 
    453    ilo_render_emit_draw_dynamic_states(render, vec, &session);
    454    ilo_render_emit_draw_surface_states(render, vec, &session);
    455 
    456    /* force all commands to be uploaded if the HW context changed */
    457    if (render->hw_ctx_changed)
    458       session.pipe_dirty = ILO_DIRTY_ALL;
    459    else
    460       session.pipe_dirty = vec->dirty;
    461 
    462    ilo_render_emit_draw_commands(render, vec, &session);
    463 
    464    draw_session_end(render, vec, &session);
    465 }
    466 
    467 int
    468 ilo_render_get_launch_grid_len(const struct ilo_render *render,
    469                                const struct ilo_state_vector *vec)
    470 {
    471    ILO_DEV_ASSERT(render->dev, 7, 7.5);
    472 
    473    return ilo_render_get_launch_grid_surface_states_len(render, vec) +
    474           ilo_render_get_launch_grid_dynamic_states_len(render, vec) +
    475           ilo_render_get_launch_grid_commands_len(render, vec);
    476 }
    477 
    478 void
    479 ilo_render_emit_launch_grid(struct ilo_render *render,
    480                             const struct ilo_state_vector *vec,
    481                             const unsigned thread_group_offset[3],
    482                             const unsigned thread_group_dim[3],
    483                             unsigned thread_group_size,
    484                             const struct pipe_constant_buffer *input,
    485                             uint32_t pc)
    486 {
    487    struct ilo_render_launch_grid_session session;
    488 
    489    ILO_DEV_ASSERT(render->dev, 7, 7.5);
    490 
    491    assert(input->buffer);
    492 
    493    memset(&session, 0, sizeof(session));
    494 
    495    session.thread_group_offset = thread_group_offset;
    496    session.thread_group_dim = thread_group_dim;
    497    session.thread_group_size = thread_group_size;
    498    session.input = input;
    499    session.pc = pc;
    500 
    501    ilo_render_emit_launch_grid_surface_states(render, vec, &session);
    502    ilo_render_emit_launch_grid_dynamic_states(render, vec, &session);
    503    ilo_render_emit_launch_grid_commands(render, vec, &session);
    504 }
    505