Home | History | Annotate | Download | only in nv50
      1 
      2 #include "util/u_viewport.h"
      3 
      4 #include "nv50/nv50_context.h"
      5 
      6 static inline void
      7 nv50_fb_set_null_rt(struct nouveau_pushbuf *push, unsigned i)
      8 {
      9    BEGIN_NV04(push, NV50_3D(RT_ADDRESS_HIGH(i)), 4);
     10    PUSH_DATA (push, 0);
     11    PUSH_DATA (push, 0);
     12    PUSH_DATA (push, 0);
     13    PUSH_DATA (push, 0);
     14    BEGIN_NV04(push, NV50_3D(RT_HORIZ(i)), 2);
     15    PUSH_DATA (push, 64);
     16    PUSH_DATA (push, 0);
     17 }
     18 
     19 static void
     20 nv50_validate_fb(struct nv50_context *nv50)
     21 {
     22    struct nouveau_pushbuf *push = nv50->base.pushbuf;
     23    struct pipe_framebuffer_state *fb = &nv50->framebuffer;
     24    unsigned i;
     25    unsigned ms_mode = NV50_3D_MULTISAMPLE_MODE_MS1;
     26    uint32_t array_size = 0xffff, array_mode = 0;
     27 
     28    nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_3D_FB);
     29 
     30    BEGIN_NV04(push, NV50_3D(RT_CONTROL), 1);
     31    PUSH_DATA (push, (076543210 << 4) | fb->nr_cbufs);
     32    BEGIN_NV04(push, NV50_3D(SCREEN_SCISSOR_HORIZ), 2);
     33    PUSH_DATA (push, fb->width << 16);
     34    PUSH_DATA (push, fb->height << 16);
     35 
     36    for (i = 0; i < fb->nr_cbufs; ++i) {
     37       struct nv50_miptree *mt;
     38       struct nv50_surface *sf;
     39       struct nouveau_bo *bo;
     40 
     41       if (!fb->cbufs[i]) {
     42          nv50_fb_set_null_rt(push, i);
     43          continue;
     44       }
     45 
     46       mt = nv50_miptree(fb->cbufs[i]->texture);
     47       sf = nv50_surface(fb->cbufs[i]);
     48       bo = mt->base.bo;
     49 
     50       array_size = MIN2(array_size, sf->depth);
     51       if (mt->layout_3d)
     52          array_mode = NV50_3D_RT_ARRAY_MODE_MODE_3D; /* 1 << 16 */
     53 
     54       /* can't mix 3D with ARRAY or have RTs of different depth/array_size */
     55       assert(mt->layout_3d || !array_mode || array_size == 1);
     56 
     57       BEGIN_NV04(push, NV50_3D(RT_ADDRESS_HIGH(i)), 5);
     58       PUSH_DATAh(push, mt->base.address + sf->offset);
     59       PUSH_DATA (push, mt->base.address + sf->offset);
     60       PUSH_DATA (push, nv50_format_table[sf->base.format].rt);
     61       if (likely(nouveau_bo_memtype(bo))) {
     62          assert(sf->base.texture->target != PIPE_BUFFER);
     63 
     64          PUSH_DATA (push, mt->level[sf->base.u.tex.level].tile_mode);
     65          PUSH_DATA (push, mt->layer_stride >> 2);
     66          BEGIN_NV04(push, NV50_3D(RT_HORIZ(i)), 2);
     67          PUSH_DATA (push, sf->width);
     68          PUSH_DATA (push, sf->height);
     69          BEGIN_NV04(push, NV50_3D(RT_ARRAY_MODE), 1);
     70          PUSH_DATA (push, array_mode | array_size);
     71          nv50->rt_array_mode = array_mode | array_size;
     72       } else {
     73          PUSH_DATA (push, 0);
     74          PUSH_DATA (push, 0);
     75          BEGIN_NV04(push, NV50_3D(RT_HORIZ(i)), 2);
     76          PUSH_DATA (push, NV50_3D_RT_HORIZ_LINEAR | mt->level[0].pitch);
     77          PUSH_DATA (push, sf->height);
     78          BEGIN_NV04(push, NV50_3D(RT_ARRAY_MODE), 1);
     79          PUSH_DATA (push, 0);
     80 
     81          assert(!fb->zsbuf);
     82          assert(!mt->ms_mode);
     83       }
     84 
     85       ms_mode = mt->ms_mode;
     86 
     87       if (mt->base.status & NOUVEAU_BUFFER_STATUS_GPU_READING)
     88          nv50->state.rt_serialize = true;
     89       mt->base.status |= NOUVEAU_BUFFER_STATUS_GPU_WRITING;
     90       mt->base.status &= ~NOUVEAU_BUFFER_STATUS_GPU_READING;
     91 
     92       /* only register for writing, otherwise we'd always serialize here */
     93       BCTX_REFN(nv50->bufctx_3d, 3D_FB, &mt->base, WR);
     94    }
     95 
     96    if (fb->zsbuf) {
     97       struct nv50_miptree *mt = nv50_miptree(fb->zsbuf->texture);
     98       struct nv50_surface *sf = nv50_surface(fb->zsbuf);
     99       int unk = mt->base.base.target == PIPE_TEXTURE_3D || sf->depth == 1;
    100 
    101       BEGIN_NV04(push, NV50_3D(ZETA_ADDRESS_HIGH), 5);
    102       PUSH_DATAh(push, mt->base.address + sf->offset);
    103       PUSH_DATA (push, mt->base.address + sf->offset);
    104       PUSH_DATA (push, nv50_format_table[fb->zsbuf->format].rt);
    105       PUSH_DATA (push, mt->level[sf->base.u.tex.level].tile_mode);
    106       PUSH_DATA (push, mt->layer_stride >> 2);
    107       BEGIN_NV04(push, NV50_3D(ZETA_ENABLE), 1);
    108       PUSH_DATA (push, 1);
    109       BEGIN_NV04(push, NV50_3D(ZETA_HORIZ), 3);
    110       PUSH_DATA (push, sf->width);
    111       PUSH_DATA (push, sf->height);
    112       PUSH_DATA (push, (unk << 16) | sf->depth);
    113 
    114       ms_mode = mt->ms_mode;
    115 
    116       if (mt->base.status & NOUVEAU_BUFFER_STATUS_GPU_READING)
    117          nv50->state.rt_serialize = true;
    118       mt->base.status |= NOUVEAU_BUFFER_STATUS_GPU_WRITING;
    119       mt->base.status &= ~NOUVEAU_BUFFER_STATUS_GPU_READING;
    120 
    121       BCTX_REFN(nv50->bufctx_3d, 3D_FB, &mt->base, WR);
    122    } else {
    123       BEGIN_NV04(push, NV50_3D(ZETA_ENABLE), 1);
    124       PUSH_DATA (push, 0);
    125    }
    126 
    127    BEGIN_NV04(push, NV50_3D(MULTISAMPLE_MODE), 1);
    128    PUSH_DATA (push, ms_mode);
    129 
    130    /* Only need to initialize the first viewport, which is used for clears */
    131    BEGIN_NV04(push, NV50_3D(VIEWPORT_HORIZ(0)), 2);
    132    PUSH_DATA (push, fb->width << 16);
    133    PUSH_DATA (push, fb->height << 16);
    134 
    135    if (nv50->screen->tesla->oclass >= NVA3_3D_CLASS) {
    136       unsigned ms = 1 << ms_mode;
    137       BEGIN_NV04(push, NV50_3D(CB_ADDR), 1);
    138       PUSH_DATA (push, (NV50_CB_AUX_SAMPLE_OFFSET << (8 - 2)) | NV50_CB_AUX);
    139       BEGIN_NI04(push, NV50_3D(CB_DATA(0)), 2 * ms);
    140       for (i = 0; i < ms; i++) {
    141          float xy[2];
    142          nv50->base.pipe.get_sample_position(&nv50->base.pipe, ms, i, xy);
    143          PUSH_DATAf(push, xy[0]);
    144          PUSH_DATAf(push, xy[1]);
    145       }
    146    }
    147 }
    148 
    149 static void
    150 nv50_validate_blend_colour(struct nv50_context *nv50)
    151 {
    152    struct nouveau_pushbuf *push = nv50->base.pushbuf;
    153 
    154    BEGIN_NV04(push, NV50_3D(BLEND_COLOR(0)), 4);
    155    PUSH_DATAf(push, nv50->blend_colour.color[0]);
    156    PUSH_DATAf(push, nv50->blend_colour.color[1]);
    157    PUSH_DATAf(push, nv50->blend_colour.color[2]);
    158    PUSH_DATAf(push, nv50->blend_colour.color[3]);
    159 }
    160 
    161 static void
    162 nv50_validate_stencil_ref(struct nv50_context *nv50)
    163 {
    164    struct nouveau_pushbuf *push = nv50->base.pushbuf;
    165 
    166    BEGIN_NV04(push, NV50_3D(STENCIL_FRONT_FUNC_REF), 1);
    167    PUSH_DATA (push, nv50->stencil_ref.ref_value[0]);
    168    BEGIN_NV04(push, NV50_3D(STENCIL_BACK_FUNC_REF), 1);
    169    PUSH_DATA (push, nv50->stencil_ref.ref_value[1]);
    170 }
    171 
    172 static void
    173 nv50_validate_stipple(struct nv50_context *nv50)
    174 {
    175    struct nouveau_pushbuf *push = nv50->base.pushbuf;
    176    unsigned i;
    177 
    178    BEGIN_NV04(push, NV50_3D(POLYGON_STIPPLE_PATTERN(0)), 32);
    179    for (i = 0; i < 32; ++i)
    180       PUSH_DATA(push, util_bswap32(nv50->stipple.stipple[i]));
    181 }
    182 
    183 static void
    184 nv50_validate_scissor(struct nv50_context *nv50)
    185 {
    186    struct nouveau_pushbuf *push = nv50->base.pushbuf;
    187 #ifdef NV50_SCISSORS_CLIPPING
    188    int minx, maxx, miny, maxy, i;
    189 
    190    if (!(nv50->dirty_3d &
    191          (NV50_NEW_3D_SCISSOR | NV50_NEW_3D_VIEWPORT | NV50_NEW_3D_FRAMEBUFFER)) &&
    192        nv50->state.scissor == nv50->rast->pipe.scissor)
    193       return;
    194 
    195    if (nv50->state.scissor != nv50->rast->pipe.scissor)
    196       nv50->scissors_dirty = (1 << NV50_MAX_VIEWPORTS) - 1;
    197 
    198    nv50->state.scissor = nv50->rast->pipe.scissor;
    199 
    200    if ((nv50->dirty_3d & NV50_NEW_3D_FRAMEBUFFER) && !nv50->state.scissor)
    201       nv50->scissors_dirty = (1 << NV50_MAX_VIEWPORTS) - 1;
    202 
    203    for (i = 0; i < NV50_MAX_VIEWPORTS; i++) {
    204       struct pipe_scissor_state *s = &nv50->scissors[i];
    205       struct pipe_viewport_state *vp = &nv50->viewports[i];
    206 
    207       if (!(nv50->scissors_dirty & (1 << i)) &&
    208           !(nv50->viewports_dirty & (1 << i)))
    209          continue;
    210 
    211       if (nv50->state.scissor) {
    212          minx = s->minx;
    213          maxx = s->maxx;
    214          miny = s->miny;
    215          maxy = s->maxy;
    216       } else {
    217          minx = 0;
    218          maxx = nv50->framebuffer.width;
    219          miny = 0;
    220          maxy = nv50->framebuffer.height;
    221       }
    222 
    223       minx = MAX2(minx, (int)(vp->translate[0] - fabsf(vp->scale[0])));
    224       maxx = MIN2(maxx, (int)(vp->translate[0] + fabsf(vp->scale[0])));
    225       miny = MAX2(miny, (int)(vp->translate[1] - fabsf(vp->scale[1])));
    226       maxy = MIN2(maxy, (int)(vp->translate[1] + fabsf(vp->scale[1])));
    227 
    228       minx = MIN2(minx, 8192);
    229       maxx = MAX2(maxx, 0);
    230       miny = MIN2(miny, 8192);
    231       maxy = MAX2(maxy, 0);
    232 
    233       BEGIN_NV04(push, NV50_3D(SCISSOR_HORIZ(i)), 2);
    234       PUSH_DATA (push, (maxx << 16) | minx);
    235       PUSH_DATA (push, (maxy << 16) | miny);
    236 #else
    237       BEGIN_NV04(push, NV50_3D(SCISSOR_HORIZ(i)), 2);
    238       PUSH_DATA (push, (s->maxx << 16) | s->minx);
    239       PUSH_DATA (push, (s->maxy << 16) | s->miny);
    240 #endif
    241    }
    242 
    243    nv50->scissors_dirty = 0;
    244 }
    245 
    246 static void
    247 nv50_validate_viewport(struct nv50_context *nv50)
    248 {
    249    struct nouveau_pushbuf *push = nv50->base.pushbuf;
    250    float zmin, zmax;
    251    int i;
    252 
    253    for (i = 0; i < NV50_MAX_VIEWPORTS; i++) {
    254       struct pipe_viewport_state *vpt = &nv50->viewports[i];
    255 
    256       if (!(nv50->viewports_dirty & (1 << i)))
    257          continue;
    258 
    259       BEGIN_NV04(push, NV50_3D(VIEWPORT_TRANSLATE_X(i)), 3);
    260       PUSH_DATAf(push, vpt->translate[0]);
    261       PUSH_DATAf(push, vpt->translate[1]);
    262       PUSH_DATAf(push, vpt->translate[2]);
    263       BEGIN_NV04(push, NV50_3D(VIEWPORT_SCALE_X(i)), 3);
    264       PUSH_DATAf(push, vpt->scale[0]);
    265       PUSH_DATAf(push, vpt->scale[1]);
    266       PUSH_DATAf(push, vpt->scale[2]);
    267 
    268       /* If the halfz setting ever changes, the viewports will also get
    269        * updated. The rast will get updated before the validate function has a
    270        * chance to hit, so we can just use it directly without an atom
    271        * dependency.
    272        */
    273       util_viewport_zmin_zmax(vpt, nv50->rast->pipe.clip_halfz, &zmin, &zmax);
    274 
    275 #ifdef NV50_SCISSORS_CLIPPING
    276       BEGIN_NV04(push, NV50_3D(DEPTH_RANGE_NEAR(i)), 2);
    277       PUSH_DATAf(push, zmin);
    278       PUSH_DATAf(push, zmax);
    279 #endif
    280    }
    281 
    282    nv50->viewports_dirty = 0;
    283 }
    284 
    285 static void
    286 nv50_validate_window_rects(struct nv50_context *nv50)
    287 {
    288    struct nouveau_pushbuf *push = nv50->base.pushbuf;
    289    bool enable = nv50->window_rect.rects > 0 || nv50->window_rect.inclusive;
    290    int i;
    291 
    292    BEGIN_NV04(push, NV50_3D(CLIP_RECTS_EN), 1);
    293    PUSH_DATA (push, enable);
    294    if (!enable)
    295       return;
    296 
    297    BEGIN_NV04(push, NV50_3D(CLIP_RECTS_MODE), 1);
    298    PUSH_DATA (push, !nv50->window_rect.inclusive);
    299    BEGIN_NV04(push, NV50_3D(CLIP_RECT_HORIZ(0)), NV50_MAX_WINDOW_RECTANGLES * 2);
    300    for (i = 0; i < nv50->window_rect.rects; i++) {
    301       struct pipe_scissor_state *s = &nv50->window_rect.rect[i];
    302       PUSH_DATA(push, (s->maxx << 16) | s->minx);
    303       PUSH_DATA(push, (s->maxy << 16) | s->miny);
    304    }
    305    for (; i < NV50_MAX_WINDOW_RECTANGLES; i++) {
    306       PUSH_DATA(push, 0);
    307       PUSH_DATA(push, 0);
    308    }
    309 }
    310 
    311 static inline void
    312 nv50_check_program_ucps(struct nv50_context *nv50,
    313                         struct nv50_program *vp, uint8_t mask)
    314 {
    315    const unsigned n = util_logbase2(mask) + 1;
    316 
    317    if (vp->vp.clpd_nr >= n)
    318       return;
    319    nv50_program_destroy(nv50, vp);
    320 
    321    vp->vp.clpd_nr = n;
    322    if (likely(vp == nv50->vertprog)) {
    323       nv50->dirty_3d |= NV50_NEW_3D_VERTPROG;
    324       nv50_vertprog_validate(nv50);
    325    } else {
    326       nv50->dirty_3d |= NV50_NEW_3D_GMTYPROG;
    327       nv50_gmtyprog_validate(nv50);
    328    }
    329    nv50_fp_linkage_validate(nv50);
    330 }
    331 
    332 /* alpha test is disabled if there are no color RTs, so make sure we have at
    333  * least one if alpha test is enabled. Note that this must run after
    334  * nv50_validate_fb, otherwise that will override the RT count setting.
    335  */
    336 static void
    337 nv50_validate_derived_2(struct nv50_context *nv50)
    338 {
    339    struct nouveau_pushbuf *push = nv50->base.pushbuf;
    340 
    341    if (nv50->zsa && nv50->zsa->pipe.alpha.enabled &&
    342        nv50->framebuffer.nr_cbufs == 0) {
    343       nv50_fb_set_null_rt(push, 0);
    344       BEGIN_NV04(push, NV50_3D(RT_CONTROL), 1);
    345       PUSH_DATA (push, (076543210 << 4) | 1);
    346    }
    347 }
    348 
    349 static void
    350 nv50_validate_clip(struct nv50_context *nv50)
    351 {
    352    struct nouveau_pushbuf *push = nv50->base.pushbuf;
    353    struct nv50_program *vp;
    354    uint8_t clip_enable = nv50->rast->pipe.clip_plane_enable;
    355 
    356    if (nv50->dirty_3d & NV50_NEW_3D_CLIP) {
    357       BEGIN_NV04(push, NV50_3D(CB_ADDR), 1);
    358       PUSH_DATA (push, (NV50_CB_AUX_UCP_OFFSET << 8) | NV50_CB_AUX);
    359       BEGIN_NI04(push, NV50_3D(CB_DATA(0)), PIPE_MAX_CLIP_PLANES * 4);
    360       PUSH_DATAp(push, &nv50->clip.ucp[0][0], PIPE_MAX_CLIP_PLANES * 4);
    361    }
    362 
    363    vp = nv50->gmtyprog;
    364    if (likely(!vp))
    365       vp = nv50->vertprog;
    366 
    367    if (clip_enable)
    368       nv50_check_program_ucps(nv50, vp, clip_enable);
    369 
    370    clip_enable &= vp->vp.clip_enable;
    371    clip_enable |= vp->vp.cull_enable;
    372 
    373    BEGIN_NV04(push, NV50_3D(CLIP_DISTANCE_ENABLE), 1);
    374    PUSH_DATA (push, clip_enable);
    375 
    376    if (nv50->state.clip_mode != vp->vp.clip_mode) {
    377       nv50->state.clip_mode = vp->vp.clip_mode;
    378       BEGIN_NV04(push, NV50_3D(CLIP_DISTANCE_MODE), 1);
    379       PUSH_DATA (push, vp->vp.clip_mode);
    380    }
    381 }
    382 
    383 static void
    384 nv50_validate_blend(struct nv50_context *nv50)
    385 {
    386    struct nouveau_pushbuf *push = nv50->base.pushbuf;
    387 
    388    PUSH_SPACE(push, nv50->blend->size);
    389    PUSH_DATAp(push, nv50->blend->state, nv50->blend->size);
    390 }
    391 
    392 static void
    393 nv50_validate_zsa(struct nv50_context *nv50)
    394 {
    395    struct nouveau_pushbuf *push = nv50->base.pushbuf;
    396 
    397    PUSH_SPACE(push, nv50->zsa->size);
    398    PUSH_DATAp(push, nv50->zsa->state, nv50->zsa->size);
    399 }
    400 
    401 static void
    402 nv50_validate_rasterizer(struct nv50_context *nv50)
    403 {
    404    struct nouveau_pushbuf *push = nv50->base.pushbuf;
    405 
    406    PUSH_SPACE(push, nv50->rast->size);
    407    PUSH_DATAp(push, nv50->rast->state, nv50->rast->size);
    408 }
    409 
    410 static void
    411 nv50_validate_sample_mask(struct nv50_context *nv50)
    412 {
    413    struct nouveau_pushbuf *push = nv50->base.pushbuf;
    414 
    415    unsigned mask[4] =
    416    {
    417       nv50->sample_mask & 0xffff,
    418       nv50->sample_mask & 0xffff,
    419       nv50->sample_mask & 0xffff,
    420       nv50->sample_mask & 0xffff
    421    };
    422 
    423    BEGIN_NV04(push, NV50_3D(MSAA_MASK(0)), 4);
    424    PUSH_DATA (push, mask[0]);
    425    PUSH_DATA (push, mask[1]);
    426    PUSH_DATA (push, mask[2]);
    427    PUSH_DATA (push, mask[3]);
    428 }
    429 
    430 static void
    431 nv50_validate_min_samples(struct nv50_context *nv50)
    432 {
    433    struct nouveau_pushbuf *push = nv50->base.pushbuf;
    434    int samples;
    435 
    436    if (nv50->screen->tesla->oclass < NVA3_3D_CLASS)
    437       return;
    438 
    439    samples = util_next_power_of_two(nv50->min_samples);
    440    if (samples > 1)
    441       samples |= NVA3_3D_SAMPLE_SHADING_ENABLE;
    442 
    443    BEGIN_NV04(push, SUBC_3D(NVA3_3D_SAMPLE_SHADING), 1);
    444    PUSH_DATA (push, samples);
    445 }
    446 
    447 static void
    448 nv50_switch_pipe_context(struct nv50_context *ctx_to)
    449 {
    450    struct nv50_context *ctx_from = ctx_to->screen->cur_ctx;
    451 
    452    if (ctx_from)
    453       ctx_to->state = ctx_from->state;
    454    else
    455       ctx_to->state = ctx_to->screen->save_state;
    456 
    457    ctx_to->dirty_3d = ~0;
    458    ctx_to->dirty_cp = ~0;
    459    ctx_to->viewports_dirty = ~0;
    460    ctx_to->scissors_dirty = ~0;
    461 
    462    ctx_to->constbuf_dirty[0] =
    463    ctx_to->constbuf_dirty[1] =
    464    ctx_to->constbuf_dirty[2] = (1 << NV50_MAX_PIPE_CONSTBUFS) - 1;
    465 
    466    if (!ctx_to->vertex)
    467       ctx_to->dirty_3d &= ~(NV50_NEW_3D_VERTEX | NV50_NEW_3D_ARRAYS);
    468 
    469    if (!ctx_to->vertprog)
    470       ctx_to->dirty_3d &= ~NV50_NEW_3D_VERTPROG;
    471    if (!ctx_to->fragprog)
    472       ctx_to->dirty_3d &= ~NV50_NEW_3D_FRAGPROG;
    473 
    474    if (!ctx_to->blend)
    475       ctx_to->dirty_3d &= ~NV50_NEW_3D_BLEND;
    476    if (!ctx_to->rast)
    477 #ifdef NV50_SCISSORS_CLIPPING
    478       ctx_to->dirty_3d &= ~(NV50_NEW_3D_RASTERIZER | NV50_NEW_3D_SCISSOR);
    479 #else
    480       ctx_to->dirty_3d &= ~NV50_NEW_3D_RASTERIZER;
    481 #endif
    482    if (!ctx_to->zsa)
    483       ctx_to->dirty_3d &= ~NV50_NEW_3D_ZSA;
    484 
    485    ctx_to->screen->cur_ctx = ctx_to;
    486 }
    487 
    488 static struct nv50_state_validate
    489 validate_list_3d[] = {
    490     { nv50_validate_fb,            NV50_NEW_3D_FRAMEBUFFER },
    491     { nv50_validate_blend,         NV50_NEW_3D_BLEND },
    492     { nv50_validate_zsa,           NV50_NEW_3D_ZSA },
    493     { nv50_validate_sample_mask,   NV50_NEW_3D_SAMPLE_MASK },
    494     { nv50_validate_rasterizer,    NV50_NEW_3D_RASTERIZER },
    495     { nv50_validate_blend_colour,  NV50_NEW_3D_BLEND_COLOUR },
    496     { nv50_validate_stencil_ref,   NV50_NEW_3D_STENCIL_REF },
    497     { nv50_validate_stipple,       NV50_NEW_3D_STIPPLE },
    498 #ifdef NV50_SCISSORS_CLIPPING
    499     { nv50_validate_scissor,       NV50_NEW_3D_SCISSOR | NV50_NEW_3D_VIEWPORT |
    500                                    NV50_NEW_3D_RASTERIZER |
    501                                    NV50_NEW_3D_FRAMEBUFFER },
    502 #else
    503     { nv50_validate_scissor,       NV50_NEW_3D_SCISSOR },
    504 #endif
    505     { nv50_validate_viewport,      NV50_NEW_3D_VIEWPORT },
    506     { nv50_validate_window_rects,  NV50_NEW_3D_WINDOW_RECTS },
    507     { nv50_vertprog_validate,      NV50_NEW_3D_VERTPROG },
    508     { nv50_gmtyprog_validate,      NV50_NEW_3D_GMTYPROG },
    509     { nv50_fragprog_validate,      NV50_NEW_3D_FRAGPROG | NV50_NEW_3D_RASTERIZER |
    510                                    NV50_NEW_3D_MIN_SAMPLES | NV50_NEW_3D_ZSA |
    511                                    NV50_NEW_3D_FRAMEBUFFER},
    512     { nv50_fp_linkage_validate,    NV50_NEW_3D_FRAGPROG | NV50_NEW_3D_VERTPROG |
    513                                    NV50_NEW_3D_GMTYPROG | NV50_NEW_3D_RASTERIZER },
    514     { nv50_gp_linkage_validate,    NV50_NEW_3D_GMTYPROG | NV50_NEW_3D_VERTPROG },
    515     { nv50_validate_derived_rs,    NV50_NEW_3D_FRAGPROG | NV50_NEW_3D_RASTERIZER |
    516                                    NV50_NEW_3D_VERTPROG | NV50_NEW_3D_GMTYPROG },
    517     { nv50_validate_derived_2,     NV50_NEW_3D_ZSA | NV50_NEW_3D_FRAMEBUFFER },
    518     { nv50_validate_clip,          NV50_NEW_3D_CLIP | NV50_NEW_3D_RASTERIZER |
    519                                    NV50_NEW_3D_VERTPROG | NV50_NEW_3D_GMTYPROG },
    520     { nv50_constbufs_validate,     NV50_NEW_3D_CONSTBUF },
    521     { nv50_validate_textures,      NV50_NEW_3D_TEXTURES },
    522     { nv50_validate_samplers,      NV50_NEW_3D_SAMPLERS },
    523     { nv50_stream_output_validate, NV50_NEW_3D_STRMOUT |
    524                                    NV50_NEW_3D_VERTPROG | NV50_NEW_3D_GMTYPROG },
    525     { nv50_vertex_arrays_validate, NV50_NEW_3D_VERTEX | NV50_NEW_3D_ARRAYS },
    526     { nv50_validate_min_samples,   NV50_NEW_3D_MIN_SAMPLES },
    527 };
    528 
    529 bool
    530 nv50_state_validate(struct nv50_context *nv50, uint32_t mask,
    531                     struct nv50_state_validate *validate_list, int size,
    532                     uint32_t *dirty, struct nouveau_bufctx *bufctx)
    533 {
    534    uint32_t state_mask;
    535    int ret;
    536    unsigned i;
    537 
    538    if (nv50->screen->cur_ctx != nv50)
    539       nv50_switch_pipe_context(nv50);
    540 
    541    state_mask = *dirty & mask;
    542 
    543    if (state_mask) {
    544       for (i = 0; i < size; i++) {
    545          struct nv50_state_validate *validate = &validate_list[i];
    546 
    547          if (state_mask & validate->states)
    548             validate->func(nv50);
    549       }
    550       *dirty &= ~state_mask;
    551 
    552       if (nv50->state.rt_serialize) {
    553          nv50->state.rt_serialize = false;
    554          BEGIN_NV04(nv50->base.pushbuf, SUBC_3D(NV50_GRAPH_SERIALIZE), 1);
    555          PUSH_DATA (nv50->base.pushbuf, 0);
    556       }
    557 
    558       nv50_bufctx_fence(bufctx, false);
    559    }
    560    nouveau_pushbuf_bufctx(nv50->base.pushbuf, bufctx);
    561    ret = nouveau_pushbuf_validate(nv50->base.pushbuf);
    562 
    563    return !ret;
    564 }
    565 
    566 bool
    567 nv50_state_validate_3d(struct nv50_context *nv50, uint32_t mask)
    568 {
    569    bool ret;
    570 
    571    ret = nv50_state_validate(nv50, mask, validate_list_3d,
    572                              ARRAY_SIZE(validate_list_3d), &nv50->dirty_3d,
    573                              nv50->bufctx_3d);
    574 
    575    if (unlikely(nv50->state.flushed)) {
    576       nv50->state.flushed = false;
    577       nv50_bufctx_fence(nv50->bufctx_3d, true);
    578    }
    579    return ret;
    580 }
    581