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