Home | History | Annotate | Download | only in i965
      1 /*
      2  * Copyright  2011 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 
     24 /** \file gen6_sol.c
     25  *
     26  * Code to initialize the binding table entries used by transform feedback.
     27  */
     28 
     29 #include "main/bufferobj.h"
     30 #include "main/macros.h"
     31 #include "brw_context.h"
     32 #include "intel_batchbuffer.h"
     33 #include "brw_defines.h"
     34 #include "brw_state.h"
     35 #include "main/transformfeedback.h"
     36 
     37 static void
     38 gen6_update_sol_surfaces(struct brw_context *brw)
     39 {
     40    struct gl_context *ctx = &brw->ctx;
     41    bool xfb_active = _mesa_is_xfb_active_and_unpaused(ctx);
     42    struct gl_transform_feedback_object *xfb_obj;
     43    const struct gl_transform_feedback_info *linked_xfb_info = NULL;
     44 
     45    if (xfb_active) {
     46       /* BRW_NEW_TRANSFORM_FEEDBACK */
     47       xfb_obj = ctx->TransformFeedback.CurrentObject;
     48       linked_xfb_info = xfb_obj->program->sh.LinkedTransformFeedback;
     49    }
     50 
     51    for (int i = 0; i < BRW_MAX_SOL_BINDINGS; ++i) {
     52       const int surf_index = SURF_INDEX_GEN6_SOL_BINDING(i);
     53       if (xfb_active && i < linked_xfb_info->NumOutputs) {
     54          unsigned buffer = linked_xfb_info->Outputs[i].OutputBuffer;
     55          unsigned buffer_offset =
     56             xfb_obj->Offset[buffer] / 4 +
     57             linked_xfb_info->Outputs[i].DstOffset;
     58          if (brw->geometry_program) {
     59             brw_update_sol_surface(
     60                brw, xfb_obj->Buffers[buffer],
     61                &brw->gs.base.surf_offset[surf_index],
     62                linked_xfb_info->Outputs[i].NumComponents,
     63                linked_xfb_info->Buffers[buffer].Stride, buffer_offset);
     64          } else {
     65             brw_update_sol_surface(
     66                brw, xfb_obj->Buffers[buffer],
     67                &brw->ff_gs.surf_offset[surf_index],
     68                linked_xfb_info->Outputs[i].NumComponents,
     69                linked_xfb_info->Buffers[buffer].Stride, buffer_offset);
     70          }
     71       } else {
     72          if (!brw->geometry_program)
     73             brw->ff_gs.surf_offset[surf_index] = 0;
     74          else
     75             brw->gs.base.surf_offset[surf_index] = 0;
     76       }
     77    }
     78 
     79    brw->ctx.NewDriverState |= BRW_NEW_SURFACES;
     80 }
     81 
     82 const struct brw_tracked_state gen6_sol_surface = {
     83    .dirty = {
     84       .mesa = 0,
     85       .brw = BRW_NEW_BATCH |
     86              BRW_NEW_BLORP |
     87              BRW_NEW_TRANSFORM_FEEDBACK,
     88    },
     89    .emit = gen6_update_sol_surfaces,
     90 };
     91 
     92 /**
     93  * Constructs the binding table for the WM surface state, which maps unit
     94  * numbers to surface state objects.
     95  */
     96 static void
     97 brw_gs_upload_binding_table(struct brw_context *brw)
     98 {
     99    uint32_t *bind;
    100    struct gl_context *ctx = &brw->ctx;
    101    const struct gl_shader_program *shaderprog;
    102    bool need_binding_table = false;
    103 
    104    /* We have two scenarios here:
    105     * 1) We are using a geometry shader only to implement transform feedback
    106     *    for a vertex shader (brw->geometry_program == NULL). In this case, we
    107     *    only need surfaces for transform feedback in the GS stage.
    108     * 2) We have a user-provided geometry shader. In this case we may need
    109     *    surfaces for transform feedback and/or other stuff, like textures,
    110     *    in the GS stage.
    111     */
    112 
    113    if (!brw->geometry_program) {
    114       /* BRW_NEW_VERTEX_PROGRAM */
    115       shaderprog = ctx->_Shader->CurrentProgram[MESA_SHADER_VERTEX];
    116       if (shaderprog) {
    117          /* Skip making a binding table if we don't have anything to put in it */
    118          const struct gl_transform_feedback_info *linked_xfb_info =
    119             shaderprog->xfb_program->sh.LinkedTransformFeedback;
    120          need_binding_table = linked_xfb_info->NumOutputs > 0;
    121       }
    122       if (!need_binding_table) {
    123          if (brw->ff_gs.bind_bo_offset != 0) {
    124             brw->ctx.NewDriverState |= BRW_NEW_BINDING_TABLE_POINTERS;
    125             brw->ff_gs.bind_bo_offset = 0;
    126          }
    127          return;
    128       }
    129 
    130       /* Might want to calculate nr_surfaces first, to avoid taking up so much
    131        * space for the binding table. Anyway, in this case we know that we only
    132        * use BRW_MAX_SOL_BINDINGS surfaces at most.
    133        */
    134       bind = brw_state_batch(brw, AUB_TRACE_BINDING_TABLE,
    135                              sizeof(uint32_t) * BRW_MAX_SOL_BINDINGS,
    136                              32, &brw->ff_gs.bind_bo_offset);
    137 
    138       /* BRW_NEW_SURFACES */
    139       memcpy(bind, brw->ff_gs.surf_offset,
    140              BRW_MAX_SOL_BINDINGS * sizeof(uint32_t));
    141    } else {
    142       /* BRW_NEW_GEOMETRY_PROGRAM */
    143       shaderprog = ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY];
    144       if (shaderprog) {
    145          /* Skip making a binding table if we don't have anything to put in it */
    146          struct brw_stage_prog_data *prog_data = brw->gs.base.prog_data;
    147          const struct gl_transform_feedback_info *linked_xfb_info =
    148             shaderprog->xfb_program->sh.LinkedTransformFeedback;
    149          need_binding_table = linked_xfb_info->NumOutputs > 0 ||
    150                               prog_data->binding_table.size_bytes > 0;
    151       }
    152       if (!need_binding_table) {
    153          if (brw->gs.base.bind_bo_offset != 0) {
    154             brw->gs.base.bind_bo_offset = 0;
    155             brw->ctx.NewDriverState |= BRW_NEW_BINDING_TABLE_POINTERS;
    156          }
    157          return;
    158       }
    159 
    160       /* Might want to calculate nr_surfaces first, to avoid taking up so much
    161        * space for the binding table.
    162        */
    163       bind = brw_state_batch(brw, AUB_TRACE_BINDING_TABLE,
    164                              sizeof(uint32_t) * BRW_MAX_SURFACES,
    165                              32, &brw->gs.base.bind_bo_offset);
    166 
    167       /* BRW_NEW_SURFACES */
    168       memcpy(bind, brw->gs.base.surf_offset,
    169              BRW_MAX_SURFACES * sizeof(uint32_t));
    170    }
    171 
    172    brw->ctx.NewDriverState |= BRW_NEW_BINDING_TABLE_POINTERS;
    173 }
    174 
    175 const struct brw_tracked_state gen6_gs_binding_table = {
    176    .dirty = {
    177       .mesa = 0,
    178       .brw = BRW_NEW_BATCH |
    179              BRW_NEW_BLORP |
    180              BRW_NEW_GEOMETRY_PROGRAM |
    181              BRW_NEW_VERTEX_PROGRAM |
    182              BRW_NEW_SURFACES,
    183    },
    184    .emit = brw_gs_upload_binding_table,
    185 };
    186 
    187 struct gl_transform_feedback_object *
    188 brw_new_transform_feedback(struct gl_context *ctx, GLuint name)
    189 {
    190    struct brw_context *brw = brw_context(ctx);
    191    struct brw_transform_feedback_object *brw_obj =
    192       CALLOC_STRUCT(brw_transform_feedback_object);
    193    if (!brw_obj)
    194       return NULL;
    195 
    196    _mesa_init_transform_feedback_object(&brw_obj->base, name);
    197 
    198    brw_obj->offset_bo =
    199       drm_intel_bo_alloc(brw->bufmgr, "transform feedback offsets", 16, 64);
    200    brw_obj->prim_count_bo =
    201       drm_intel_bo_alloc(brw->bufmgr, "xfb primitive counts", 4096, 64);
    202 
    203    return &brw_obj->base;
    204 }
    205 
    206 void
    207 brw_delete_transform_feedback(struct gl_context *ctx,
    208                               struct gl_transform_feedback_object *obj)
    209 {
    210    struct brw_transform_feedback_object *brw_obj =
    211       (struct brw_transform_feedback_object *) obj;
    212 
    213    for (unsigned i = 0; i < ARRAY_SIZE(obj->Buffers); i++) {
    214       _mesa_reference_buffer_object(ctx, &obj->Buffers[i], NULL);
    215    }
    216 
    217    drm_intel_bo_unreference(brw_obj->offset_bo);
    218    drm_intel_bo_unreference(brw_obj->prim_count_bo);
    219 
    220    free(brw_obj);
    221 }
    222 
    223 void
    224 brw_begin_transform_feedback(struct gl_context *ctx, GLenum mode,
    225 			     struct gl_transform_feedback_object *obj)
    226 {
    227    struct brw_context *brw = brw_context(ctx);
    228    const struct gl_shader_program *shaderprog;
    229    const struct gl_transform_feedback_info *linked_xfb_info;
    230    struct gl_transform_feedback_object *xfb_obj =
    231       ctx->TransformFeedback.CurrentObject;
    232 
    233    assert(brw->gen == 6);
    234 
    235    if (ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]) {
    236       /* BRW_NEW_GEOMETRY_PROGRAM */
    237       shaderprog =
    238          ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY];
    239    } else {
    240       /* BRW_NEW_VERTEX_PROGRAM */
    241       shaderprog =
    242          ctx->_Shader->CurrentProgram[MESA_SHADER_VERTEX];
    243    }
    244    linked_xfb_info = shaderprog->xfb_program->sh.LinkedTransformFeedback;
    245 
    246    /* Compute the maximum number of vertices that we can write without
    247     * overflowing any of the buffers currently being used for feedback.
    248     */
    249    unsigned max_index
    250       = _mesa_compute_max_transform_feedback_vertices(ctx, xfb_obj,
    251                                                       linked_xfb_info);
    252 
    253    /* Initialize the SVBI 0 register to zero and set the maximum index. */
    254    BEGIN_BATCH(4);
    255    OUT_BATCH(_3DSTATE_GS_SVB_INDEX << 16 | (4 - 2));
    256    OUT_BATCH(0); /* SVBI 0 */
    257    OUT_BATCH(0); /* starting index */
    258    OUT_BATCH(max_index);
    259    ADVANCE_BATCH();
    260 
    261    /* Initialize the rest of the unused streams to sane values.  Otherwise,
    262     * they may indicate that there is no room to write data and prevent
    263     * anything from happening at all.
    264     */
    265    for (int i = 1; i < 4; i++) {
    266       BEGIN_BATCH(4);
    267       OUT_BATCH(_3DSTATE_GS_SVB_INDEX << 16 | (4 - 2));
    268       OUT_BATCH(i << SVB_INDEX_SHIFT);
    269       OUT_BATCH(0); /* starting index */
    270       OUT_BATCH(0xffffffff);
    271       ADVANCE_BATCH();
    272    }
    273 }
    274 
    275 void
    276 brw_end_transform_feedback(struct gl_context *ctx,
    277                            struct gl_transform_feedback_object *obj)
    278 {
    279    /* After EndTransformFeedback, it's likely that the client program will try
    280     * to draw using the contents of the transform feedback buffer as vertex
    281     * input.  In order for this to work, we need to flush the data through at
    282     * least the GS stage of the pipeline, and flush out the render cache.  For
    283     * simplicity, just do a full flush.
    284     */
    285    struct brw_context *brw = brw_context(ctx);
    286    brw_emit_mi_flush(brw);
    287 }
    288