Home | History | Annotate | Download | only in nvc0
      1 /*
      2  * Copyright 2010 Christoph Bumiller
      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 shall be included in
     12  * all copies or substantial portions of the Software.
     13  *
     14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     17  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20  * OTHER DEALINGS IN THE SOFTWARE.
     21  */
     22 
     23 #include "pipe/p_context.h"
     24 #include "pipe/p_defines.h"
     25 #include "pipe/p_state.h"
     26 #include "util/u_inlines.h"
     27 
     28 #include "nvc0/nvc0_context.h"
     29 #include "nvc0/nvc0_query_hw.h"
     30 
     31 #include "nvc0/nvc0_compute.xml.h"
     32 
     33 static inline void
     34 nvc0_program_update_context_state(struct nvc0_context *nvc0,
     35                                   struct nvc0_program *prog, int stage)
     36 {
     37    if (prog && prog->need_tls) {
     38       const uint32_t flags = NV_VRAM_DOMAIN(&nvc0->screen->base) | NOUVEAU_BO_RDWR;
     39       if (!nvc0->state.tls_required)
     40          BCTX_REFN_bo(nvc0->bufctx_3d, 3D_TLS, flags, nvc0->screen->tls);
     41       nvc0->state.tls_required |= 1 << stage;
     42    } else {
     43       if (nvc0->state.tls_required == (1 << stage))
     44          nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_3D_TLS);
     45       nvc0->state.tls_required &= ~(1 << stage);
     46    }
     47 }
     48 
     49 static inline bool
     50 nvc0_program_validate(struct nvc0_context *nvc0, struct nvc0_program *prog)
     51 {
     52    if (prog->mem)
     53       return true;
     54 
     55    if (!prog->translated) {
     56       prog->translated = nvc0_program_translate(
     57          prog, nvc0->screen->base.device->chipset, &nvc0->base.debug);
     58       if (!prog->translated)
     59          return false;
     60    }
     61 
     62    if (likely(prog->code_size))
     63       return nvc0_program_upload(nvc0, prog);
     64    return true; /* stream output info only */
     65 }
     66 
     67 void
     68 nvc0_vertprog_validate(struct nvc0_context *nvc0)
     69 {
     70    struct nouveau_pushbuf *push = nvc0->base.pushbuf;
     71    struct nvc0_program *vp = nvc0->vertprog;
     72 
     73    if (!nvc0_program_validate(nvc0, vp))
     74          return;
     75    nvc0_program_update_context_state(nvc0, vp, 0);
     76 
     77    BEGIN_NVC0(push, NVC0_3D(SP_SELECT(1)), 2);
     78    PUSH_DATA (push, 0x11);
     79    PUSH_DATA (push, vp->code_base);
     80    BEGIN_NVC0(push, NVC0_3D(SP_GPR_ALLOC(1)), 1);
     81    PUSH_DATA (push, vp->num_gprs);
     82 
     83    // BEGIN_NVC0(push, NVC0_3D_(0x163c), 1);
     84    // PUSH_DATA (push, 0);
     85 }
     86 
     87 void
     88 nvc0_fragprog_validate(struct nvc0_context *nvc0)
     89 {
     90    struct nouveau_pushbuf *push = nvc0->base.pushbuf;
     91    struct nvc0_program *fp = nvc0->fragprog;
     92    struct pipe_rasterizer_state *rast = &nvc0->rast->pipe;
     93 
     94    if (fp->fp.force_persample_interp != rast->force_persample_interp) {
     95       /* Force the program to be reuploaded, which will trigger interp fixups
     96        * to get applied
     97        */
     98       if (fp->mem)
     99          nouveau_heap_free(&fp->mem);
    100 
    101       fp->fp.force_persample_interp = rast->force_persample_interp;
    102    }
    103 
    104    /* Shade model works well enough when both colors follow it. However if one
    105     * (or both) is explicitly set, then we have to go the patching route.
    106     */
    107    bool has_explicit_color = fp->fp.colors &&
    108       (((fp->fp.colors & 1) && !fp->fp.color_interp[0]) ||
    109        ((fp->fp.colors & 2) && !fp->fp.color_interp[1]));
    110    bool hwflatshade = false;
    111    if (has_explicit_color && fp->fp.flatshade != rast->flatshade) {
    112       /* Force re-upload */
    113       if (fp->mem)
    114          nouveau_heap_free(&fp->mem);
    115 
    116       fp->fp.flatshade = rast->flatshade;
    117 
    118       /* Always smooth-shade in this mode, the shader will decide on its own
    119        * when to flat-shade.
    120        */
    121    } else if (!has_explicit_color) {
    122       hwflatshade = rast->flatshade;
    123 
    124       /* No need to binary-patch the shader each time, make sure that it's set
    125        * up for the default behaviour.
    126        */
    127       fp->fp.flatshade = 0;
    128    }
    129 
    130    if (hwflatshade != nvc0->state.flatshade) {
    131       nvc0->state.flatshade = hwflatshade;
    132       BEGIN_NVC0(push, NVC0_3D(SHADE_MODEL), 1);
    133       PUSH_DATA (push, hwflatshade ? NVC0_3D_SHADE_MODEL_FLAT :
    134                                      NVC0_3D_SHADE_MODEL_SMOOTH);
    135    }
    136 
    137    if (fp->mem && !(nvc0->dirty_3d & NVC0_NEW_3D_FRAGPROG)) {
    138       return;
    139    }
    140 
    141    if (!nvc0_program_validate(nvc0, fp))
    142          return;
    143    nvc0_program_update_context_state(nvc0, fp, 4);
    144 
    145    if (fp->fp.early_z != nvc0->state.early_z_forced) {
    146       nvc0->state.early_z_forced = fp->fp.early_z;
    147       IMMED_NVC0(push, NVC0_3D(FORCE_EARLY_FRAGMENT_TESTS), fp->fp.early_z);
    148    }
    149 
    150    BEGIN_NVC0(push, NVC0_3D(SP_SELECT(5)), 2);
    151    PUSH_DATA (push, 0x51);
    152    PUSH_DATA (push, fp->code_base);
    153    BEGIN_NVC0(push, NVC0_3D(SP_GPR_ALLOC(5)), 1);
    154    PUSH_DATA (push, fp->num_gprs);
    155 
    156    BEGIN_NVC0(push, SUBC_3D(0x0360), 2);
    157    PUSH_DATA (push, 0x20164010);
    158    PUSH_DATA (push, 0x20);
    159    BEGIN_NVC0(push, NVC0_3D(ZCULL_TEST_MASK), 1);
    160    PUSH_DATA (push, fp->flags[0]);
    161 }
    162 
    163 void
    164 nvc0_tctlprog_validate(struct nvc0_context *nvc0)
    165 {
    166    struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    167    struct nvc0_program *tp = nvc0->tctlprog;
    168 
    169    if (tp && nvc0_program_validate(nvc0, tp)) {
    170       if (tp->tp.tess_mode != ~0) {
    171          BEGIN_NVC0(push, NVC0_3D(TESS_MODE), 1);
    172          PUSH_DATA (push, tp->tp.tess_mode);
    173       }
    174       BEGIN_NVC0(push, NVC0_3D(SP_SELECT(2)), 2);
    175       PUSH_DATA (push, 0x21);
    176       PUSH_DATA (push, tp->code_base);
    177       BEGIN_NVC0(push, NVC0_3D(SP_GPR_ALLOC(2)), 1);
    178       PUSH_DATA (push, tp->num_gprs);
    179    } else {
    180       tp = nvc0->tcp_empty;
    181       /* not a whole lot we can do to handle this failure */
    182       if (!nvc0_program_validate(nvc0, tp))
    183          assert(!"unable to validate empty tcp");
    184       BEGIN_NVC0(push, NVC0_3D(SP_SELECT(2)), 2);
    185       PUSH_DATA (push, 0x20);
    186       PUSH_DATA (push, tp->code_base);
    187    }
    188    nvc0_program_update_context_state(nvc0, tp, 1);
    189 }
    190 
    191 void
    192 nvc0_tevlprog_validate(struct nvc0_context *nvc0)
    193 {
    194    struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    195    struct nvc0_program *tp = nvc0->tevlprog;
    196 
    197    if (tp && nvc0_program_validate(nvc0, tp)) {
    198       if (tp->tp.tess_mode != ~0) {
    199          BEGIN_NVC0(push, NVC0_3D(TESS_MODE), 1);
    200          PUSH_DATA (push, tp->tp.tess_mode);
    201       }
    202       BEGIN_NVC0(push, NVC0_3D(MACRO_TEP_SELECT), 1);
    203       PUSH_DATA (push, 0x31);
    204       BEGIN_NVC0(push, NVC0_3D(SP_START_ID(3)), 1);
    205       PUSH_DATA (push, tp->code_base);
    206       BEGIN_NVC0(push, NVC0_3D(SP_GPR_ALLOC(3)), 1);
    207       PUSH_DATA (push, tp->num_gprs);
    208    } else {
    209       BEGIN_NVC0(push, NVC0_3D(MACRO_TEP_SELECT), 1);
    210       PUSH_DATA (push, 0x30);
    211    }
    212    nvc0_program_update_context_state(nvc0, tp, 2);
    213 }
    214 
    215 void
    216 nvc0_gmtyprog_validate(struct nvc0_context *nvc0)
    217 {
    218    struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    219    struct nvc0_program *gp = nvc0->gmtyprog;
    220 
    221    /* we allow GPs with no code for specifying stream output state only */
    222    if (gp && nvc0_program_validate(nvc0, gp) && gp->code_size) {
    223       const bool gp_selects_layer = !!(gp->hdr[13] & (1 << 9));
    224 
    225       BEGIN_NVC0(push, NVC0_3D(MACRO_GP_SELECT), 1);
    226       PUSH_DATA (push, 0x41);
    227       BEGIN_NVC0(push, NVC0_3D(SP_START_ID(4)), 1);
    228       PUSH_DATA (push, gp->code_base);
    229       BEGIN_NVC0(push, NVC0_3D(SP_GPR_ALLOC(4)), 1);
    230       PUSH_DATA (push, gp->num_gprs);
    231       BEGIN_NVC0(push, NVC0_3D(LAYER), 1);
    232       PUSH_DATA (push, gp_selects_layer ? NVC0_3D_LAYER_USE_GP : 0);
    233    } else {
    234       IMMED_NVC0(push, NVC0_3D(LAYER), 0);
    235       BEGIN_NVC0(push, NVC0_3D(MACRO_GP_SELECT), 1);
    236       PUSH_DATA (push, 0x40);
    237    }
    238    nvc0_program_update_context_state(nvc0, gp, 3);
    239 }
    240 
    241 void
    242 nvc0_compprog_validate(struct nvc0_context *nvc0)
    243 {
    244    struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    245    struct nvc0_program *cp = nvc0->compprog;
    246 
    247    if (cp && !nvc0_program_validate(nvc0, cp))
    248       return;
    249 
    250    BEGIN_NVC0(push, NVC0_CP(FLUSH), 1);
    251    PUSH_DATA (push, NVC0_COMPUTE_FLUSH_CODE);
    252 }
    253 
    254 void
    255 nvc0_tfb_validate(struct nvc0_context *nvc0)
    256 {
    257    struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    258    struct nvc0_transform_feedback_state *tfb;
    259    unsigned b;
    260 
    261    if (nvc0->gmtyprog) tfb = nvc0->gmtyprog->tfb;
    262    else
    263    if (nvc0->tevlprog) tfb = nvc0->tevlprog->tfb;
    264    else
    265       tfb = nvc0->vertprog->tfb;
    266 
    267    IMMED_NVC0(push, NVC0_3D(TFB_ENABLE), (tfb && nvc0->num_tfbbufs) ? 1 : 0);
    268 
    269    if (tfb && tfb != nvc0->state.tfb) {
    270       for (b = 0; b < 4; ++b) {
    271          if (tfb->varying_count[b]) {
    272             unsigned n = (tfb->varying_count[b] + 3) / 4;
    273 
    274             BEGIN_NVC0(push, NVC0_3D(TFB_STREAM(b)), 3);
    275             PUSH_DATA (push, tfb->stream[b]);
    276             PUSH_DATA (push, tfb->varying_count[b]);
    277             PUSH_DATA (push, tfb->stride[b]);
    278             BEGIN_NVC0(push, NVC0_3D(TFB_VARYING_LOCS(b, 0)), n);
    279             PUSH_DATAp(push, tfb->varying_index[b], n);
    280 
    281             if (nvc0->tfbbuf[b])
    282                nvc0_so_target(nvc0->tfbbuf[b])->stride = tfb->stride[b];
    283          } else {
    284             IMMED_NVC0(push, NVC0_3D(TFB_VARYING_COUNT(b)), 0);
    285          }
    286       }
    287    }
    288    nvc0->state.tfb = tfb;
    289 
    290    if (!(nvc0->dirty_3d & NVC0_NEW_3D_TFB_TARGETS))
    291       return;
    292 
    293    for (b = 0; b < nvc0->num_tfbbufs; ++b) {
    294       struct nvc0_so_target *targ = nvc0_so_target(nvc0->tfbbuf[b]);
    295       struct nv04_resource *buf;
    296 
    297       if (!targ) {
    298          IMMED_NVC0(push, NVC0_3D(TFB_BUFFER_ENABLE(b)), 0);
    299          continue;
    300       }
    301 
    302       if (tfb)
    303          targ->stride = tfb->stride[b];
    304 
    305       buf = nv04_resource(targ->pipe.buffer);
    306 
    307       BCTX_REFN(nvc0->bufctx_3d, 3D_TFB, buf, WR);
    308 
    309       if (!(nvc0->tfbbuf_dirty & (1 << b)))
    310          continue;
    311 
    312       if (!targ->clean)
    313          nvc0_hw_query_fifo_wait(nvc0, nvc0_query(targ->pq));
    314       nouveau_pushbuf_space(push, 0, 0, 1);
    315       BEGIN_NVC0(push, NVC0_3D(TFB_BUFFER_ENABLE(b)), 5);
    316       PUSH_DATA (push, 1);
    317       PUSH_DATAh(push, buf->address + targ->pipe.buffer_offset);
    318       PUSH_DATA (push, buf->address + targ->pipe.buffer_offset);
    319       PUSH_DATA (push, targ->pipe.buffer_size);
    320       if (!targ->clean) {
    321          nvc0_hw_query_pushbuf_submit(push, nvc0_query(targ->pq), 0x4);
    322       } else {
    323          PUSH_DATA(push, 0); /* TFB_BUFFER_OFFSET */
    324          targ->clean = false;
    325       }
    326    }
    327    for (; b < 4; ++b)
    328       IMMED_NVC0(push, NVC0_3D(TFB_BUFFER_ENABLE(b)), 0);
    329 }
    330