Home | History | Annotate | Download | only in i965
      1 /*
      2  * Copyright  2012 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  *    Jordan Justen <jordan.l.justen (at) intel.com>
     25  *
     26  */
     27 
     28 #include "main/imports.h"
     29 #include "main/bufferobj.h"
     30 #include "main/varray.h"
     31 #include "vbo/vbo.h"
     32 
     33 #include "brw_context.h"
     34 #include "brw_defines.h"
     35 #include "brw_draw.h"
     36 
     37 #include "intel_batchbuffer.h"
     38 
     39 /**
     40  * Check if the hardware's cut index support can handle the primitive
     41  * restart index value (pre-Haswell only).
     42  */
     43 static bool
     44 can_cut_index_handle_restart_index(struct gl_context *ctx,
     45                                    const struct _mesa_index_buffer *ib)
     46 {
     47    /* The FixedIndex variant means 0xFF, 0xFFFF, or 0xFFFFFFFF based on
     48     * the index buffer type, which corresponds exactly to the hardware.
     49     */
     50    if (ctx->Array.PrimitiveRestartFixedIndex)
     51       return true;
     52 
     53    bool cut_index_will_work;
     54 
     55    switch (ib->type) {
     56    case GL_UNSIGNED_BYTE:
     57       cut_index_will_work = ctx->Array.RestartIndex == 0xff;
     58       break;
     59    case GL_UNSIGNED_SHORT:
     60       cut_index_will_work = ctx->Array.RestartIndex == 0xffff;
     61       break;
     62    case GL_UNSIGNED_INT:
     63       cut_index_will_work = ctx->Array.RestartIndex == 0xffffffff;
     64       break;
     65    default:
     66       unreachable("not reached");
     67    }
     68 
     69    return cut_index_will_work;
     70 }
     71 
     72 /**
     73  * Check if the hardware's cut index support can handle the primitive
     74  * restart case.
     75  */
     76 static bool
     77 can_cut_index_handle_prims(struct gl_context *ctx,
     78                            const struct _mesa_prim *prim,
     79                            GLuint nr_prims,
     80                            const struct _mesa_index_buffer *ib)
     81 {
     82    struct brw_context *brw = brw_context(ctx);
     83 
     84    /* Otherwise Haswell can do it all. */
     85    if (brw->gen >= 8 || brw->is_haswell)
     86       return true;
     87 
     88    if (!can_cut_index_handle_restart_index(ctx, ib)) {
     89       /* The primitive restart index can't be handled, so take
     90        * the software path
     91        */
     92       return false;
     93    }
     94 
     95    for (unsigned i = 0; i < nr_prims; i++) {
     96       switch (prim[i].mode) {
     97       case GL_POINTS:
     98       case GL_LINES:
     99       case GL_LINE_STRIP:
    100       case GL_TRIANGLES:
    101       case GL_TRIANGLE_STRIP:
    102       case GL_LINES_ADJACENCY:
    103       case GL_LINE_STRIP_ADJACENCY:
    104       case GL_TRIANGLES_ADJACENCY:
    105       case GL_TRIANGLE_STRIP_ADJACENCY:
    106          /* Cut index supports these primitive types */
    107          break;
    108       default:
    109          /* Cut index does not support these primitive types */
    110       //case GL_LINE_LOOP:
    111       //case GL_TRIANGLE_FAN:
    112       //case GL_QUADS:
    113       //case GL_QUAD_STRIP:
    114       //case GL_POLYGON:
    115          return false;
    116       }
    117    }
    118 
    119    return true;
    120 }
    121 
    122 /**
    123  * Check if primitive restart is enabled, and if so, handle it properly.
    124  *
    125  * In some cases the support will be handled in software. When available
    126  * hardware will handle primitive restart.
    127  */
    128 GLboolean
    129 brw_handle_primitive_restart(struct gl_context *ctx,
    130                              const struct _mesa_prim *prims,
    131                              GLuint nr_prims,
    132                              const struct _mesa_index_buffer *ib,
    133                              struct gl_buffer_object *indirect)
    134 {
    135    struct brw_context *brw = brw_context(ctx);
    136 
    137    /* We only need to handle cases where there is an index buffer. */
    138    if (ib == NULL) {
    139       return GL_FALSE;
    140    }
    141 
    142    /* If we have set the in_progress flag, then we are in the middle
    143     * of handling the primitive restart draw.
    144     */
    145    if (brw->prim_restart.in_progress) {
    146       return GL_FALSE;
    147    }
    148 
    149    /* If PrimitiveRestart is not enabled, then we aren't concerned about
    150     * handling this draw.
    151     */
    152    if (!(ctx->Array._PrimitiveRestart)) {
    153       return GL_FALSE;
    154    }
    155 
    156    /* Signal that we are in the process of handling the
    157     * primitive restart draw
    158     */
    159    brw->prim_restart.in_progress = true;
    160 
    161    if (can_cut_index_handle_prims(ctx, prims, nr_prims, ib)) {
    162       /* Cut index should work for primitive restart, so use it
    163        */
    164       brw->prim_restart.enable_cut_index = true;
    165       brw_draw_prims(ctx, prims, nr_prims, ib, GL_FALSE, -1, -1, NULL, 0,
    166                      indirect);
    167       brw->prim_restart.enable_cut_index = false;
    168    } else {
    169       /* Not all the primitive draw modes are supported by the cut index,
    170        * so take the software path
    171        */
    172       vbo_sw_primitive_restart(ctx, prims, nr_prims, ib, indirect);
    173    }
    174 
    175    brw->prim_restart.in_progress = false;
    176 
    177    /* The primitive restart draw was completed, so return true. */
    178    return GL_TRUE;
    179 }
    180 
    181 static void
    182 haswell_upload_cut_index(struct brw_context *brw)
    183 {
    184    struct gl_context *ctx = &brw->ctx;
    185 
    186    /* Don't trigger on Ivybridge */
    187    if (brw->gen < 8 && !brw->is_haswell)
    188       return;
    189 
    190    const unsigned cut_index_setting =
    191       ctx->Array._PrimitiveRestart ? HSW_CUT_INDEX_ENABLE : 0;
    192 
    193    /* BRW_NEW_INDEX_BUFFER */
    194    unsigned cut_index;
    195    if (brw->ib.ib) {
    196       cut_index = _mesa_primitive_restart_index(ctx, brw->ib.type);
    197    } else {
    198       /* There's no index buffer, but primitive restart may still apply
    199        * to glDrawArrays and such.  FIXED_INDEX mode only applies to drawing
    200        * operations that use an index buffer, so we can ignore it and use
    201        * the GL restart index directly.
    202        */
    203       cut_index = ctx->Array.RestartIndex;
    204    }
    205 
    206    BEGIN_BATCH(2);
    207    OUT_BATCH(_3DSTATE_VF << 16 | cut_index_setting | (2 - 2));
    208    OUT_BATCH(cut_index);
    209    ADVANCE_BATCH();
    210 }
    211 
    212 const struct brw_tracked_state haswell_cut_index = {
    213    .dirty = {
    214       .mesa  = _NEW_TRANSFORM,
    215       .brw   = BRW_NEW_BLORP |
    216                BRW_NEW_INDEX_BUFFER,
    217    },
    218    .emit = haswell_upload_cut_index,
    219 };
    220