Home | History | Annotate | Download | only in nvc0
      1 
      2 #include "util/u_math.h"
      3 
      4 #include "nvc0_context.h"
      5 
      6 static void
      7 nvc0_validate_zcull(struct nvc0_context *nvc0)
      8 {
      9     struct nouveau_pushbuf *push = nvc0->base.pushbuf;
     10     struct pipe_framebuffer_state *fb = &nvc0->framebuffer;
     11     struct nv50_surface *sf = nv50_surface(fb->zsbuf);
     12     struct nv50_miptree *mt = nv50_miptree(sf->base.texture);
     13     struct nouveau_bo *bo = mt->base.bo;
     14     uint32_t size;
     15     uint32_t offset = align(mt->total_size, 1 << 17);
     16     unsigned width, height;
     17 
     18     assert(mt->base.base.depth0 == 1 && mt->base.base.array_size < 2);
     19 
     20     size = mt->total_size * 2;
     21 
     22     height = align(fb->height, 32);
     23     width = fb->width % 224;
     24     if (width)
     25        width = fb->width + (224 - width);
     26     else
     27        width = fb->width;
     28 
     29     BEGIN_NVC0(push, NVC0_3D(ZCULL_REGION), 1);
     30     PUSH_DATA (push, 0);
     31     BEGIN_NVC0(push, NVC0_3D(ZCULL_ADDRESS_HIGH), 2);
     32     PUSH_DATAh(push, bo->offset + offset);
     33     PUSH_DATA (push, bo->offset + offset);
     34     offset += 1 << 17;
     35     BEGIN_NVC0(push, NVC0_3D(ZCULL_LIMIT_HIGH), 2);
     36     PUSH_DATAh(push, bo->offset + offset);
     37     PUSH_DATA (push, bo->offset + offset);
     38     BEGIN_NVC0(push, SUBC_3D(0x07e0), 2);
     39     PUSH_DATA (push, size);
     40     PUSH_DATA (push, size >> 16);
     41     BEGIN_NVC0(push, SUBC_3D(0x15c8), 1); /* bits 0x3 */
     42     PUSH_DATA (push, 2);
     43     BEGIN_NVC0(push, NVC0_3D(ZCULL_WIDTH), 4);
     44     PUSH_DATA (push, width);
     45     PUSH_DATA (push, height);
     46     PUSH_DATA (push, 1);
     47     PUSH_DATA (push, 0);
     48     BEGIN_NVC0(push, NVC0_3D(ZCULL_WINDOW_OFFSET_X), 2);
     49     PUSH_DATA (push, 0);
     50     PUSH_DATA (push, 0);
     51     BEGIN_NVC0(push, NVC0_3D(ZCULL_INVALIDATE), 1);
     52     PUSH_DATA (push, 0);
     53 }
     54 
     55 static void
     56 nvc0_validate_fb(struct nvc0_context *nvc0)
     57 {
     58     struct nouveau_pushbuf *push = nvc0->base.pushbuf;
     59     struct pipe_framebuffer_state *fb = &nvc0->framebuffer;
     60     unsigned i;
     61     unsigned ms_mode = NVC0_3D_MULTISAMPLE_MODE_MS1;
     62     boolean serialize = FALSE;
     63 
     64     nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_FB);
     65 
     66     BEGIN_NVC0(push, NVC0_3D(RT_CONTROL), 1);
     67     PUSH_DATA (push, (076543210 << 4) | fb->nr_cbufs);
     68     BEGIN_NVC0(push, NVC0_3D(SCREEN_SCISSOR_HORIZ), 2);
     69     PUSH_DATA (push, fb->width << 16);
     70     PUSH_DATA (push, fb->height << 16);
     71 
     72     for (i = 0; i < fb->nr_cbufs; ++i) {
     73         struct nv50_surface *sf = nv50_surface(fb->cbufs[i]);
     74         struct nv04_resource *res = nv04_resource(sf->base.texture);
     75         struct nouveau_bo *bo = res->bo;
     76 
     77         BEGIN_NVC0(push, NVC0_3D(RT_ADDRESS_HIGH(i)), 9);
     78         PUSH_DATAh(push, res->address + sf->offset);
     79         PUSH_DATA (push, res->address + sf->offset);
     80         if (likely(nouveau_bo_memtype(bo))) {
     81            struct nv50_miptree *mt = nv50_miptree(sf->base.texture);
     82 
     83            assert(sf->base.texture->target != PIPE_BUFFER);
     84 
     85            PUSH_DATA(push, sf->width);
     86            PUSH_DATA(push, sf->height);
     87            PUSH_DATA(push, nvc0_format_table[sf->base.format].rt);
     88            PUSH_DATA(push, (mt->layout_3d << 16) |
     89                     mt->level[sf->base.u.tex.level].tile_mode);
     90            PUSH_DATA(push, sf->base.u.tex.first_layer + sf->depth);
     91            PUSH_DATA(push, mt->layer_stride >> 2);
     92            PUSH_DATA(push, sf->base.u.tex.first_layer);
     93 
     94            ms_mode = mt->ms_mode;
     95         } else {
     96            if (res->base.target == PIPE_BUFFER) {
     97               PUSH_DATA(push, 262144);
     98               PUSH_DATA(push, 1);
     99            } else {
    100               PUSH_DATA(push, nv50_miptree(sf->base.texture)->level[0].pitch);
    101               PUSH_DATA(push, sf->height);
    102            }
    103            PUSH_DATA(push, nvc0_format_table[sf->base.format].rt);
    104            PUSH_DATA(push, 1 << 12);
    105            PUSH_DATA(push, 1);
    106            PUSH_DATA(push, 0);
    107            PUSH_DATA(push, 0);
    108 
    109            nvc0_resource_fence(res, NOUVEAU_BO_WR);
    110 
    111            assert(!fb->zsbuf);
    112         }
    113 
    114         if (res->status & NOUVEAU_BUFFER_STATUS_GPU_READING)
    115            serialize = TRUE;
    116         res->status |=  NOUVEAU_BUFFER_STATUS_GPU_WRITING;
    117         res->status &= ~NOUVEAU_BUFFER_STATUS_GPU_READING;
    118 
    119         /* only register for writing, otherwise we'd always serialize here */
    120         BCTX_REFN(nvc0->bufctx_3d, FB, res, WR);
    121     }
    122 
    123     if (fb->zsbuf) {
    124         struct nv50_miptree *mt = nv50_miptree(fb->zsbuf->texture);
    125         struct nv50_surface *sf = nv50_surface(fb->zsbuf);
    126         int unk = mt->base.base.target == PIPE_TEXTURE_2D;
    127 
    128         BEGIN_NVC0(push, NVC0_3D(ZETA_ADDRESS_HIGH), 5);
    129         PUSH_DATAh(push, mt->base.address + sf->offset);
    130         PUSH_DATA (push, mt->base.address + sf->offset);
    131         PUSH_DATA (push, nvc0_format_table[fb->zsbuf->format].rt);
    132         PUSH_DATA (push, mt->level[sf->base.u.tex.level].tile_mode);
    133         PUSH_DATA (push, mt->layer_stride >> 2);
    134         BEGIN_NVC0(push, NVC0_3D(ZETA_ENABLE), 1);
    135         PUSH_DATA (push, 1);
    136         BEGIN_NVC0(push, NVC0_3D(ZETA_HORIZ), 3);
    137         PUSH_DATA (push, sf->width);
    138         PUSH_DATA (push, sf->height);
    139         PUSH_DATA (push, (unk << 16) |
    140                    (sf->base.u.tex.first_layer + sf->depth));
    141         BEGIN_NVC0(push, NVC0_3D(ZETA_BASE_LAYER), 1);
    142         PUSH_DATA (push, sf->base.u.tex.first_layer);
    143 
    144         ms_mode = mt->ms_mode;
    145 
    146         if (mt->base.status & NOUVEAU_BUFFER_STATUS_GPU_READING)
    147            serialize = TRUE;
    148         mt->base.status |=  NOUVEAU_BUFFER_STATUS_GPU_WRITING;
    149         mt->base.status &= ~NOUVEAU_BUFFER_STATUS_GPU_READING;
    150 
    151         BCTX_REFN(nvc0->bufctx_3d, FB, &mt->base, WR);
    152     } else {
    153         BEGIN_NVC0(push, NVC0_3D(ZETA_ENABLE), 1);
    154         PUSH_DATA (push, 0);
    155     }
    156 
    157     IMMED_NVC0(push, NVC0_3D(MULTISAMPLE_MODE), ms_mode);
    158 
    159     if (serialize)
    160        IMMED_NVC0(push, NVC0_3D(SERIALIZE), 0);
    161 }
    162 
    163 static void
    164 nvc0_validate_blend_colour(struct nvc0_context *nvc0)
    165 {
    166    struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    167 
    168    BEGIN_NVC0(push, NVC0_3D(BLEND_COLOR(0)), 4);
    169    PUSH_DATAf(push, nvc0->blend_colour.color[0]);
    170    PUSH_DATAf(push, nvc0->blend_colour.color[1]);
    171    PUSH_DATAf(push, nvc0->blend_colour.color[2]);
    172    PUSH_DATAf(push, nvc0->blend_colour.color[3]);
    173 }
    174 
    175 static void
    176 nvc0_validate_stencil_ref(struct nvc0_context *nvc0)
    177 {
    178     struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    179     const ubyte *ref = &nvc0->stencil_ref.ref_value[0];
    180 
    181     IMMED_NVC0(push, NVC0_3D(STENCIL_FRONT_FUNC_REF), ref[0]);
    182     IMMED_NVC0(push, NVC0_3D(STENCIL_BACK_FUNC_REF), ref[1]);
    183 }
    184 
    185 static void
    186 nvc0_validate_stipple(struct nvc0_context *nvc0)
    187 {
    188     struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    189     unsigned i;
    190 
    191     BEGIN_NVC0(push, NVC0_3D(POLYGON_STIPPLE_PATTERN(0)), 32);
    192     for (i = 0; i < 32; ++i)
    193         PUSH_DATA(push, util_bswap32(nvc0->stipple.stipple[i]));
    194 }
    195 
    196 static void
    197 nvc0_validate_scissor(struct nvc0_context *nvc0)
    198 {
    199     struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    200     struct pipe_scissor_state *s = &nvc0->scissor;
    201 
    202     if (!(nvc0->dirty & NVC0_NEW_SCISSOR) &&
    203         nvc0->rast->pipe.scissor == nvc0->state.scissor)
    204        return;
    205     nvc0->state.scissor = nvc0->rast->pipe.scissor;
    206 
    207     BEGIN_NVC0(push, NVC0_3D(SCISSOR_HORIZ(0)), 2);
    208     if (nvc0->rast->pipe.scissor) {
    209        PUSH_DATA(push, (s->maxx << 16) | s->minx);
    210        PUSH_DATA(push, (s->maxy << 16) | s->miny);
    211     } else {
    212        PUSH_DATA(push, (0xffff << 16) | 0);
    213        PUSH_DATA(push, (0xffff << 16) | 0);
    214     }
    215 }
    216 
    217 static void
    218 nvc0_validate_viewport(struct nvc0_context *nvc0)
    219 {
    220     struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    221     struct pipe_viewport_state *vp = &nvc0->viewport;
    222     int x, y, w, h;
    223     float zmin, zmax;
    224 
    225     BEGIN_NVC0(push, NVC0_3D(VIEWPORT_TRANSLATE_X(0)), 3);
    226     PUSH_DATAf(push, vp->translate[0]);
    227     PUSH_DATAf(push, vp->translate[1]);
    228     PUSH_DATAf(push, vp->translate[2]);
    229     BEGIN_NVC0(push, NVC0_3D(VIEWPORT_SCALE_X(0)), 3);
    230     PUSH_DATAf(push, vp->scale[0]);
    231     PUSH_DATAf(push, vp->scale[1]);
    232     PUSH_DATAf(push, vp->scale[2]);
    233 
    234     /* now set the viewport rectangle to viewport dimensions for clipping */
    235 
    236     x = util_iround(MAX2(0.0f, vp->translate[0] - fabsf(vp->scale[0])));
    237     y = util_iround(MAX2(0.0f, vp->translate[1] - fabsf(vp->scale[1])));
    238     w = util_iround(vp->translate[0] + fabsf(vp->scale[0])) - x;
    239     h = util_iround(vp->translate[1] + fabsf(vp->scale[1])) - y;
    240 
    241     zmin = vp->translate[2] - fabsf(vp->scale[2]);
    242     zmax = vp->translate[2] + fabsf(vp->scale[2]);
    243 
    244     BEGIN_NVC0(push, NVC0_3D(VIEWPORT_HORIZ(0)), 2);
    245     PUSH_DATA (push, (w << 16) | x);
    246     PUSH_DATA (push, (h << 16) | y);
    247     BEGIN_NVC0(push, NVC0_3D(DEPTH_RANGE_NEAR(0)), 2);
    248     PUSH_DATAf(push, zmin);
    249     PUSH_DATAf(push, zmax);
    250 }
    251 
    252 static INLINE void
    253 nvc0_upload_uclip_planes(struct nvc0_context *nvc0, unsigned s)
    254 {
    255    struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    256    struct nouveau_bo *bo = nvc0->screen->uniform_bo;
    257 
    258    BEGIN_NVC0(push, NVC0_3D(CB_SIZE), 3);
    259    PUSH_DATA (push, 512);
    260    PUSH_DATAh(push, bo->offset + (5 << 16) + (s << 9));
    261    PUSH_DATA (push, bo->offset + (5 << 16) + (s << 9));
    262    BEGIN_1IC0(push, NVC0_3D(CB_POS), PIPE_MAX_CLIP_PLANES * 4 + 1);
    263    PUSH_DATA (push, 256);
    264    PUSH_DATAp(push, &nvc0->clip.ucp[0][0], PIPE_MAX_CLIP_PLANES * 4);
    265 }
    266 
    267 static INLINE void
    268 nvc0_check_program_ucps(struct nvc0_context *nvc0,
    269                         struct nvc0_program *vp, uint8_t mask)
    270 {
    271    const unsigned n = util_logbase2(mask) + 1;
    272 
    273    if (vp->vp.num_ucps >= n)
    274       return;
    275    nvc0_program_destroy(nvc0, vp);
    276 
    277    vp->vp.num_ucps = n;
    278    if (likely(vp == nvc0->vertprog))
    279       nvc0_vertprog_validate(nvc0);
    280    else
    281    if (likely(vp == nvc0->gmtyprog))
    282       nvc0_vertprog_validate(nvc0);
    283    else
    284       nvc0_tevlprog_validate(nvc0);
    285 }
    286 
    287 static void
    288 nvc0_validate_clip(struct nvc0_context *nvc0)
    289 {
    290    struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    291    struct nvc0_program *vp;
    292    unsigned stage;
    293    uint8_t clip_enable = nvc0->rast->pipe.clip_plane_enable;
    294 
    295    if (nvc0->gmtyprog) {
    296       stage = 3;
    297       vp = nvc0->gmtyprog;
    298    } else
    299    if (nvc0->tevlprog) {
    300       stage = 2;
    301       vp = nvc0->tevlprog;
    302    } else {
    303       stage = 0;
    304       vp = nvc0->vertprog;
    305    }
    306 
    307    if (clip_enable && vp->vp.num_ucps < PIPE_MAX_CLIP_PLANES)
    308       nvc0_check_program_ucps(nvc0, vp, clip_enable);
    309 
    310    if (nvc0->dirty & (NVC0_NEW_CLIP | (NVC0_NEW_VERTPROG << stage)))
    311       if (vp->vp.num_ucps > 0 && vp->vp.num_ucps <= PIPE_MAX_CLIP_PLANES)
    312          nvc0_upload_uclip_planes(nvc0, stage);
    313 
    314    clip_enable &= vp->vp.clip_enable;
    315 
    316    if (nvc0->state.clip_enable != clip_enable) {
    317       nvc0->state.clip_enable = clip_enable;
    318       IMMED_NVC0(push, NVC0_3D(CLIP_DISTANCE_ENABLE), clip_enable);
    319    }
    320    if (nvc0->state.clip_mode != vp->vp.clip_mode) {
    321       nvc0->state.clip_mode = vp->vp.clip_mode;
    322       BEGIN_NVC0(push, NVC0_3D(CLIP_DISTANCE_MODE), 1);
    323       PUSH_DATA (push, vp->vp.clip_mode);
    324    }
    325 }
    326 
    327 static void
    328 nvc0_validate_blend(struct nvc0_context *nvc0)
    329 {
    330    struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    331 
    332    PUSH_SPACE(push, nvc0->blend->size);
    333    PUSH_DATAp(push, nvc0->blend->state, nvc0->blend->size);
    334 }
    335 
    336 static void
    337 nvc0_validate_zsa(struct nvc0_context *nvc0)
    338 {
    339    struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    340 
    341    PUSH_SPACE(push, nvc0->zsa->size);
    342    PUSH_DATAp(push, nvc0->zsa->state, nvc0->zsa->size);
    343 }
    344 
    345 static void
    346 nvc0_validate_rasterizer(struct nvc0_context *nvc0)
    347 {
    348    struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    349 
    350    PUSH_SPACE(push, nvc0->rast->size);
    351    PUSH_DATAp(push, nvc0->rast->state, nvc0->rast->size);
    352 }
    353 
    354 static void
    355 nvc0_constbufs_validate(struct nvc0_context *nvc0)
    356 {
    357    struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    358    unsigned s;
    359 
    360    for (s = 0; s < 5; ++s) {
    361       while (nvc0->constbuf_dirty[s]) {
    362          int i = ffs(nvc0->constbuf_dirty[s]) - 1;
    363          nvc0->constbuf_dirty[s] &= ~(1 << i);
    364 
    365          if (nvc0->constbuf[s][i].user) {
    366             struct nouveau_bo *bo = nvc0->screen->uniform_bo;
    367             const unsigned base = s << 16;
    368             const unsigned size = nvc0->constbuf[s][0].size;
    369             assert(i == 0); /* we really only want OpenGL uniforms here */
    370             assert(nvc0->constbuf[s][0].u.data);
    371 
    372             if (nvc0->state.uniform_buffer_bound[s] < size) {
    373                nvc0->state.uniform_buffer_bound[s] = align(size, 0x100);
    374 
    375                BEGIN_NVC0(push, NVC0_3D(CB_SIZE), 3);
    376                PUSH_DATA (push, nvc0->state.uniform_buffer_bound[s]);
    377                PUSH_DATAh(push, bo->offset + base);
    378                PUSH_DATA (push, bo->offset + base);
    379                BEGIN_NVC0(push, NVC0_3D(CB_BIND(s)), 1);
    380                PUSH_DATA (push, (0 << 4) | 1);
    381             }
    382             nvc0_cb_push(&nvc0->base, bo, NOUVEAU_BO_VRAM,
    383                          base, nvc0->state.uniform_buffer_bound[s],
    384                          0, (size + 3) / 4,
    385                          nvc0->constbuf[s][0].u.data);
    386          } else {
    387             struct nv04_resource *res =
    388                nv04_resource(nvc0->constbuf[s][i].u.buf);
    389             if (res) {
    390                BEGIN_NVC0(push, NVC0_3D(CB_SIZE), 3);
    391                PUSH_DATA (push, nvc0->constbuf[s][i].size);
    392                PUSH_DATAh(push, res->address + nvc0->constbuf[s][i].offset);
    393                PUSH_DATA (push, res->address + nvc0->constbuf[s][i].offset);
    394                BEGIN_NVC0(push, NVC0_3D(CB_BIND(s)), 1);
    395                PUSH_DATA (push, (i << 4) | 1);
    396 
    397                BCTX_REFN(nvc0->bufctx_3d, CB(s, i), res, RD);
    398             } else {
    399                BEGIN_NVC0(push, NVC0_3D(CB_BIND(s)), 1);
    400                PUSH_DATA (push, (i << 4) | 0);
    401             }
    402             if (i == 0)
    403                nvc0->state.uniform_buffer_bound[s] = 0;
    404          }
    405       }
    406    }
    407 }
    408 
    409 static void
    410 nvc0_validate_sample_mask(struct nvc0_context *nvc0)
    411 {
    412    struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    413 
    414    unsigned mask[4] =
    415    {
    416       nvc0->sample_mask & 0xffff,
    417       nvc0->sample_mask & 0xffff,
    418       nvc0->sample_mask & 0xffff,
    419       nvc0->sample_mask & 0xffff
    420    };
    421 
    422    BEGIN_NVC0(push, NVC0_3D(MSAA_MASK(0)), 4);
    423    PUSH_DATA (push, mask[0]);
    424    PUSH_DATA (push, mask[1]);
    425    PUSH_DATA (push, mask[2]);
    426    PUSH_DATA (push, mask[3]);
    427    BEGIN_NVC0(push, NVC0_3D(SAMPLE_SHADING), 1);
    428    PUSH_DATA (push, 0x01);
    429 }
    430 
    431 static void
    432 nvc0_validate_derived_1(struct nvc0_context *nvc0)
    433 {
    434    struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    435    boolean rasterizer_discard;
    436 
    437    rasterizer_discard = (!nvc0->fragprog || !nvc0->fragprog->hdr[18]) &&
    438       !nvc0->zsa->pipe.depth.enabled && !nvc0->zsa->pipe.stencil[0].enabled;
    439    rasterizer_discard = rasterizer_discard ||
    440       nvc0->rast->pipe.rasterizer_discard;
    441 
    442    if (rasterizer_discard != nvc0->state.rasterizer_discard) {
    443       nvc0->state.rasterizer_discard = rasterizer_discard;
    444       IMMED_NVC0(push, NVC0_3D(RASTERIZE_ENABLE), !rasterizer_discard);
    445    }
    446 }
    447 
    448 static void
    449 nvc0_switch_pipe_context(struct nvc0_context *ctx_to)
    450 {
    451    struct nvc0_context *ctx_from = ctx_to->screen->cur_ctx;
    452    unsigned s;
    453 
    454    if (ctx_from)
    455       ctx_to->state = ctx_from->state;
    456 
    457    ctx_to->dirty = ~0;
    458 
    459    for (s = 0; s < 5; ++s) {
    460       ctx_to->samplers_dirty[s] = ~0;
    461       ctx_to->textures_dirty[s] = ~0;
    462    }
    463 
    464    if (!ctx_to->vertex)
    465       ctx_to->dirty &= ~(NVC0_NEW_VERTEX | NVC0_NEW_ARRAYS);
    466    if (!ctx_to->idxbuf.buffer)
    467       ctx_to->dirty &= ~NVC0_NEW_IDXBUF;
    468 
    469    if (!ctx_to->vertprog)
    470       ctx_to->dirty &= ~NVC0_NEW_VERTPROG;
    471    if (!ctx_to->fragprog)
    472       ctx_to->dirty &= ~NVC0_NEW_FRAGPROG;
    473 
    474    if (!ctx_to->blend)
    475       ctx_to->dirty &= ~NVC0_NEW_BLEND;
    476    if (!ctx_to->rast)
    477       ctx_to->dirty &= ~(NVC0_NEW_RASTERIZER | NVC0_NEW_SCISSOR);
    478    if (!ctx_to->zsa)
    479       ctx_to->dirty &= ~NVC0_NEW_ZSA;
    480 
    481    ctx_to->screen->cur_ctx = ctx_to;
    482 }
    483 
    484 static struct state_validate {
    485     void (*func)(struct nvc0_context *);
    486     uint32_t states;
    487 } validate_list[] = {
    488     { nvc0_validate_fb,            NVC0_NEW_FRAMEBUFFER },
    489     { nvc0_validate_blend,         NVC0_NEW_BLEND },
    490     { nvc0_validate_zsa,           NVC0_NEW_ZSA },
    491     { nvc0_validate_sample_mask,   NVC0_NEW_SAMPLE_MASK },
    492     { nvc0_validate_rasterizer,    NVC0_NEW_RASTERIZER },
    493     { nvc0_validate_blend_colour,  NVC0_NEW_BLEND_COLOUR },
    494     { nvc0_validate_stencil_ref,   NVC0_NEW_STENCIL_REF },
    495     { nvc0_validate_stipple,       NVC0_NEW_STIPPLE },
    496     { nvc0_validate_scissor,       NVC0_NEW_SCISSOR | NVC0_NEW_RASTERIZER },
    497     { nvc0_validate_viewport,      NVC0_NEW_VIEWPORT },
    498     { nvc0_vertprog_validate,      NVC0_NEW_VERTPROG },
    499     { nvc0_tctlprog_validate,      NVC0_NEW_TCTLPROG },
    500     { nvc0_tevlprog_validate,      NVC0_NEW_TEVLPROG },
    501     { nvc0_gmtyprog_validate,      NVC0_NEW_GMTYPROG },
    502     { nvc0_fragprog_validate,      NVC0_NEW_FRAGPROG },
    503     { nvc0_validate_derived_1,     NVC0_NEW_FRAGPROG | NVC0_NEW_ZSA |
    504                                    NVC0_NEW_RASTERIZER },
    505     { nvc0_validate_clip,          NVC0_NEW_CLIP | NVC0_NEW_RASTERIZER |
    506                                    NVC0_NEW_VERTPROG |
    507                                    NVC0_NEW_TEVLPROG |
    508                                    NVC0_NEW_GMTYPROG },
    509     { nvc0_constbufs_validate,     NVC0_NEW_CONSTBUF },
    510     { nvc0_validate_textures,      NVC0_NEW_TEXTURES },
    511     { nvc0_validate_samplers,      NVC0_NEW_SAMPLERS },
    512     { nve4_set_tex_handles,        NVC0_NEW_TEXTURES | NVC0_NEW_SAMPLERS },
    513     { nvc0_vertex_arrays_validate, NVC0_NEW_VERTEX | NVC0_NEW_ARRAYS },
    514     { nvc0_idxbuf_validate,        NVC0_NEW_IDXBUF },
    515     { nvc0_tfb_validate,           NVC0_NEW_TFB_TARGETS | NVC0_NEW_GMTYPROG }
    516 };
    517 #define validate_list_len (sizeof(validate_list) / sizeof(validate_list[0]))
    518 
    519 boolean
    520 nvc0_state_validate(struct nvc0_context *nvc0, uint32_t mask, unsigned words)
    521 {
    522    uint32_t state_mask;
    523    int ret;
    524    unsigned i;
    525 
    526    if (nvc0->screen->cur_ctx != nvc0)
    527       nvc0_switch_pipe_context(nvc0);
    528 
    529    state_mask = nvc0->dirty & mask;
    530 
    531    if (state_mask) {
    532       for (i = 0; i < validate_list_len; ++i) {
    533          struct state_validate *validate = &validate_list[i];
    534 
    535          if (state_mask & validate->states)
    536             validate->func(nvc0);
    537       }
    538       nvc0->dirty &= ~state_mask;
    539 
    540       nvc0_bufctx_fence(nvc0, nvc0->bufctx_3d, FALSE);
    541    }
    542 
    543    nouveau_pushbuf_bufctx(nvc0->base.pushbuf, nvc0->bufctx_3d);
    544    ret = nouveau_pushbuf_validate(nvc0->base.pushbuf);
    545    if (unlikely(ret))
    546       return FALSE;
    547 
    548    if (unlikely(nvc0->state.flushed))
    549       nvc0_bufctx_fence(nvc0, nvc0->bufctx_3d, TRUE);
    550 
    551    return TRUE;
    552 }
    553