nv50_state_validate.c revision ef715b866b6858b79530b44ec7be61f271591adc
1/* 2 * Copyright 2008 Ben Skeggs 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 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 * SOFTWARE. 21 */ 22 23#include "util/u_format.h" 24 25#include "nv50_context.h" 26#include "nv50_resource.h" 27#include "nouveau/nouveau_stateobj.h" 28 29static struct nouveau_stateobj * 30validate_fb(struct nv50_context *nv50) 31{ 32 struct nouveau_grobj *tesla = nv50->screen->tesla; 33 struct nouveau_stateobj *so = so_new(32, 79, 18); 34 struct pipe_framebuffer_state *fb = &nv50->framebuffer; 35 unsigned i, w = 0, h = 0, gw = 0; 36 37 /* Set nr of active RTs and select RT for each colour output. 38 * FP result 0 always goes to RT[0], bits 4 - 6 are ignored. 39 * Ambiguous assignment results in no rendering (no DATA_ERROR). 40 */ 41 so_method(so, tesla, NV50TCL_RT_CONTROL, 1); 42 so_data (so, fb->nr_cbufs | 43 (0 << 4) | (1 << 7) | (2 << 10) | (3 << 13) | 44 (4 << 16) | (5 << 19) | (6 << 22) | (7 << 25)); 45 46 for (i = 0; i < fb->nr_cbufs; i++) { 47 struct pipe_resource *pt = fb->cbufs[i]->texture; 48 struct nouveau_bo *bo = nv50_miptree(pt)->base.bo; 49 50 if (!gw) { 51 w = fb->cbufs[i]->width; 52 h = fb->cbufs[i]->height; 53 gw = 1; 54 } else { 55 assert(w == fb->cbufs[i]->width); 56 assert(h == fb->cbufs[i]->height); 57 } 58 59 assert(nv50_format_table[fb->cbufs[i]->format].rt); 60 61 so_method(so, tesla, NV50TCL_RT_HORIZ(i), 2); 62 so_data (so, fb->cbufs[i]->width); 63 so_data (so, fb->cbufs[i]->height); 64 65 so_method(so, tesla, NV50TCL_RT_ADDRESS_HIGH(i), 5); 66 so_reloc (so, bo, fb->cbufs[i]->offset, NOUVEAU_BO_VRAM | 67 NOUVEAU_BO_HIGH | NOUVEAU_BO_RDWR, 0, 0); 68 so_reloc (so, bo, fb->cbufs[i]->offset, NOUVEAU_BO_VRAM | 69 NOUVEAU_BO_LOW | NOUVEAU_BO_RDWR, 0, 0); 70 so_data (so, nv50_format_table[fb->cbufs[i]->format].rt); 71 so_data (so, nv50_miptree(pt)-> 72 level[fb->cbufs[i]->level].tile_mode << 4); 73 so_data(so, 0x00000000); 74 75 so_method(so, tesla, NV50TCL_RT_ARRAY_MODE, 1); 76 so_data (so, 1); 77 } 78 79 if (fb->zsbuf) { 80 struct pipe_resource *pt = fb->zsbuf->texture; 81 struct nouveau_bo *bo = nv50_miptree(pt)->base.bo; 82 83 if (!gw) { 84 w = fb->zsbuf->width; 85 h = fb->zsbuf->height; 86 gw = 1; 87 } else { 88 assert(w == fb->zsbuf->width); 89 assert(h == fb->zsbuf->height); 90 } 91 92 assert(nv50_format_table[fb->zsbuf->format].rt); 93 94 so_method(so, tesla, NV50TCL_ZETA_ADDRESS_HIGH, 5); 95 so_reloc (so, bo, fb->zsbuf->offset, NOUVEAU_BO_VRAM | 96 NOUVEAU_BO_HIGH | NOUVEAU_BO_RDWR, 0, 0); 97 so_reloc (so, bo, fb->zsbuf->offset, NOUVEAU_BO_VRAM | 98 NOUVEAU_BO_LOW | NOUVEAU_BO_RDWR, 0, 0); 99 so_data (so, nv50_format_table[fb->zsbuf->format].rt); 100 so_data (so, nv50_miptree(pt)-> 101 level[fb->zsbuf->level].tile_mode << 4); 102 so_data (so, 0x00000000); 103 104 so_method(so, tesla, NV50TCL_ZETA_ENABLE, 1); 105 so_data (so, 1); 106 so_method(so, tesla, NV50TCL_ZETA_HORIZ, 3); 107 so_data (so, fb->zsbuf->width); 108 so_data (so, fb->zsbuf->height); 109 so_data (so, 0x00010001); 110 } else { 111 so_method(so, tesla, NV50TCL_ZETA_ENABLE, 1); 112 so_data (so, 0); 113 } 114 115 so_method(so, tesla, NV50TCL_VIEWPORT_HORIZ(0), 2); 116 so_data (so, w << 16); 117 so_data (so, h << 16); 118 /* set window lower left corner */ 119 so_method(so, tesla, NV50TCL_WINDOW_OFFSET_X, 2); 120 so_data (so, 0); 121 so_data (so, 0); 122 /* set screen scissor rectangle */ 123 so_method(so, tesla, NV50TCL_SCREEN_SCISSOR_HORIZ, 2); 124 so_data (so, w << 16); 125 so_data (so, h << 16); 126 127 return so; 128} 129 130static void 131nv50_validate_samplers(struct nv50_context *nv50, struct nouveau_stateobj *so, 132 unsigned p) 133{ 134 struct nouveau_grobj *eng2d = nv50->screen->eng2d; 135 unsigned i, j, dw = nv50->sampler_nr[p] * 8; 136 137 if (!dw) 138 return; 139 nv50_so_init_sifc(nv50, so, nv50->screen->tsc, NOUVEAU_BO_VRAM, 140 p * (32 * 8 * 4), dw * 4); 141 142 so_method(so, eng2d, NV50_2D_SIFC_DATA | (2 << 29), dw); 143 144 for (i = 0; i < nv50->sampler_nr[p]; ++i) { 145 if (nv50->sampler[p][i]) 146 so_datap(so, nv50->sampler[p][i]->tsc, 8); 147 else { 148 for (j = 0; j < 8; ++j) /* you get punished */ 149 so_data(so, 0); /* ... for leaving holes */ 150 } 151 } 152} 153 154static struct nouveau_stateobj * 155validate_blend(struct nv50_context *nv50) 156{ 157 struct nouveau_stateobj *so = NULL; 158 so_ref(nv50->blend->so, &so); 159 return so; 160} 161 162static struct nouveau_stateobj * 163validate_zsa(struct nv50_context *nv50) 164{ 165 struct nouveau_stateobj *so = NULL; 166 so_ref(nv50->zsa->so, &so); 167 return so; 168} 169 170static struct nouveau_stateobj * 171validate_rast(struct nv50_context *nv50) 172{ 173 struct nouveau_stateobj *so = NULL; 174 so_ref(nv50->rasterizer->so, &so); 175 return so; 176} 177 178static struct nouveau_stateobj * 179validate_blend_colour(struct nv50_context *nv50) 180{ 181 struct nouveau_grobj *tesla = nv50->screen->tesla; 182 struct nouveau_stateobj *so = so_new(1, 4, 0); 183 184 so_method(so, tesla, NV50TCL_BLEND_COLOR(0), 4); 185 so_data (so, fui(nv50->blend_colour.color[0])); 186 so_data (so, fui(nv50->blend_colour.color[1])); 187 so_data (so, fui(nv50->blend_colour.color[2])); 188 so_data (so, fui(nv50->blend_colour.color[3])); 189 return so; 190} 191 192static struct nouveau_stateobj * 193validate_stencil_ref(struct nv50_context *nv50) 194{ 195 struct nouveau_grobj *tesla = nv50->screen->tesla; 196 struct nouveau_stateobj *so = so_new(2, 2, 0); 197 198 so_method(so, tesla, NV50TCL_STENCIL_FRONT_FUNC_REF, 1); 199 so_data (so, nv50->stencil_ref.ref_value[0]); 200 so_method(so, tesla, NV50TCL_STENCIL_BACK_FUNC_REF, 1); 201 so_data (so, nv50->stencil_ref.ref_value[1]); 202 return so; 203} 204 205static struct nouveau_stateobj * 206validate_stipple(struct nv50_context *nv50) 207{ 208 struct nouveau_grobj *tesla = nv50->screen->tesla; 209 struct nouveau_stateobj *so = so_new(1, 32, 0); 210 int i; 211 212 so_method(so, tesla, NV50TCL_POLYGON_STIPPLE_PATTERN(0), 32); 213 for (i = 0; i < 32; i++) 214 so_data(so, util_bswap32(nv50->stipple.stipple[i])); 215 return so; 216} 217 218static struct nouveau_stateobj * 219validate_scissor(struct nv50_context *nv50) 220{ 221 struct nouveau_grobj *tesla = nv50->screen->tesla; 222 struct pipe_scissor_state *s = &nv50->scissor; 223 struct nouveau_stateobj *so; 224 225 so = so_new(1, 2, 0); 226 so_method(so, tesla, NV50TCL_SCISSOR_HORIZ(0), 2); 227 so_data (so, (s->maxx << 16) | s->minx); 228 so_data (so, (s->maxy << 16) | s->miny); 229 return so; 230} 231 232static struct nouveau_stateobj * 233validate_viewport(struct nv50_context *nv50) 234{ 235 struct nouveau_grobj *tesla = nv50->screen->tesla; 236 struct nouveau_stateobj *so = so_new(3, 7, 0); 237 238 so_method(so, tesla, NV50TCL_VIEWPORT_TRANSLATE_X(0), 3); 239 so_data (so, fui(nv50->viewport.translate[0])); 240 so_data (so, fui(nv50->viewport.translate[1])); 241 so_data (so, fui(nv50->viewport.translate[2])); 242 so_method(so, tesla, NV50TCL_VIEWPORT_SCALE_X(0), 3); 243 so_data (so, fui(nv50->viewport.scale[0])); 244 so_data (so, fui(nv50->viewport.scale[1])); 245 so_data (so, fui(nv50->viewport.scale[2])); 246 247 /* no idea what 0f90 does */ 248 so_method(so, tesla, 0x0f90, 1); 249 so_data (so, 0); 250 251 return so; 252} 253 254static struct nouveau_stateobj * 255validate_sampler(struct nv50_context *nv50) 256{ 257 struct nouveau_grobj *tesla = nv50->screen->tesla; 258 struct nouveau_stateobj *so; 259 unsigned nr = 0, i; 260 261 for (i = 0; i < 3; ++i) 262 nr += nv50->sampler_nr[i]; 263 264 so = so_new(1 + 5 * 3, 1 + 19 * 3 + nr * 8, 3 * 2); 265 266 nv50_validate_samplers(nv50, so, 0); /* VP */ 267 nv50_validate_samplers(nv50, so, 2); /* FP */ 268 269 so_method(so, tesla, 0x1334, 1); /* flush TSC */ 270 so_data (so, 0); 271 272 return so; 273} 274 275static struct nouveau_stateobj * 276validate_vtxbuf(struct nv50_context *nv50) 277{ 278 struct nouveau_stateobj *so = NULL; 279 so_ref(nv50->state.vtxbuf, &so); 280 return so; 281} 282 283static struct nouveau_stateobj * 284validate_vtxattr(struct nv50_context *nv50) 285{ 286 struct nouveau_stateobj *so = NULL; 287 so_ref(nv50->state.vtxattr, &so); 288 return so; 289} 290 291static struct nouveau_stateobj * 292validate_clip(struct nv50_context *nv50) 293{ 294 struct nouveau_grobj *tesla = nv50->screen->tesla; 295 struct nouveau_stateobj *so = so_new(1, 1, 0); 296 uint32_t vvcc; 297 298 /* 0x0000 = remove whole primitive only (xyz) 299 * 0x1018 = remove whole primitive only (xy), clamp z 300 * 0x1080 = clip primitive (xyz) 301 * 0x1098 = clip primitive (xy), clamp z 302 */ 303 vvcc = nv50->clip.depth_clamp ? 0x1098 : 0x1080; 304 305 so_method(so, tesla, NV50TCL_VIEW_VOLUME_CLIP_CTRL, 1); 306 so_data (so, vvcc); 307 308 return so; 309} 310 311struct state_validate { 312 struct nouveau_stateobj *(*func)(struct nv50_context *nv50); 313 unsigned states; 314} validate_list[] = { 315 { validate_fb , NV50_NEW_FRAMEBUFFER }, 316 { validate_blend , NV50_NEW_BLEND }, 317 { validate_zsa , NV50_NEW_ZSA }, 318 { nv50_vertprog_validate , NV50_NEW_VERTPROG | NV50_NEW_VERTPROG_CB }, 319 { nv50_fragprog_validate , NV50_NEW_FRAGPROG | NV50_NEW_FRAGPROG_CB }, 320 { nv50_geomprog_validate , NV50_NEW_GEOMPROG | NV50_NEW_GEOMPROG_CB }, 321 { nv50_fp_linkage_validate, NV50_NEW_VERTPROG | NV50_NEW_GEOMPROG | 322 NV50_NEW_FRAGPROG | NV50_NEW_RASTERIZER }, 323 { nv50_gp_linkage_validate, NV50_NEW_VERTPROG | NV50_NEW_GEOMPROG }, 324 { validate_rast , NV50_NEW_RASTERIZER }, 325 { validate_blend_colour , NV50_NEW_BLEND_COLOUR }, 326 { validate_stencil_ref , NV50_NEW_STENCIL_REF }, 327 { validate_stipple , NV50_NEW_STIPPLE }, 328 { validate_scissor , NV50_NEW_SCISSOR }, 329 { validate_viewport , NV50_NEW_VIEWPORT }, 330 { validate_sampler , NV50_NEW_SAMPLER }, 331 { nv50_tex_validate , NV50_NEW_TEXTURE | NV50_NEW_SAMPLER }, 332 { nv50_vbo_validate , NV50_NEW_ARRAYS }, 333 { validate_vtxbuf , NV50_NEW_ARRAYS }, 334 { validate_vtxattr , NV50_NEW_ARRAYS }, 335 { validate_clip , NV50_NEW_CLIP }, 336 { NULL , 0 } 337}; 338#define validate_list_len (sizeof(validate_list) / sizeof(validate_list[0])) 339 340boolean 341nv50_state_validate(struct nv50_context *nv50, unsigned wait_dwords) 342{ 343 struct nouveau_channel *chan = nv50->screen->base.channel; 344 struct nouveau_grobj *tesla = nv50->screen->tesla; 345 unsigned nr_relocs = 128, nr_dwords = wait_dwords + 128 + 4; 346 int ret, i; 347 348 for (i = 0; i < validate_list_len; i++) { 349 struct state_validate *validate = &validate_list[i]; 350 struct nouveau_stateobj *so; 351 352 if (!(nv50->dirty & validate->states)) 353 continue; 354 355 so = validate->func(nv50); 356 if (!so) 357 continue; 358 359 nr_dwords += (so->total + so->cur); 360 nr_relocs += so->cur_reloc; 361 362 so_ref(so, &nv50->state.hw[i]); 363 so_ref(NULL, &so); 364 nv50->state.hw_dirty |= (1 << i); 365 } 366 nv50->dirty = 0; 367 368 if (nv50->screen->cur_ctx != nv50) { 369 for (i = 0; i < validate_list_len; i++) { 370 if (!nv50->state.hw[i] || 371 (nv50->state.hw_dirty & (1 << i))) 372 continue; 373 374 nr_dwords += (nv50->state.hw[i]->total + 375 nv50->state.hw[i]->cur); 376 nr_relocs += nv50->state.hw[i]->cur_reloc; 377 nv50->state.hw_dirty |= (1 << i); 378 } 379 380 nv50->screen->cur_ctx = nv50; 381 } 382 383 ret = MARK_RING(chan, nr_dwords, nr_relocs); 384 if (ret) { 385 debug_printf("MARK_RING(%d, %d) failed: %d\n", 386 nr_dwords, nr_relocs, ret); 387 return FALSE; 388 } 389 390 while (nv50->state.hw_dirty) { 391 i = ffs(nv50->state.hw_dirty) - 1; 392 nv50->state.hw_dirty &= ~(1 << i); 393 394 so_emit(chan, nv50->state.hw[i]); 395 } 396 397 /* Yes, really, we need to do this. If a buffer that is referenced 398 * on the hardware isn't part of changed state above, without doing 399 * this the kernel is given no clue that the buffer is being used 400 * still. This can cause all sorts of fun issues. 401 */ 402 nv50_tex_relocs(nv50); 403 so_emit_reloc_markers(chan, nv50->state.hw[0]); /* fb */ 404 so_emit_reloc_markers(chan, nv50->state.hw[3]); /* vp */ 405 so_emit_reloc_markers(chan, nv50->state.hw[4]); /* fp */ 406 so_emit_reloc_markers(chan, nv50->state.hw[17]); /* vb */ 407 nv50_screen_relocs(nv50->screen); 408 409 /* No idea.. */ 410 BEGIN_RING(chan, tesla, 0x142c, 1); 411 OUT_RING (chan, 0); 412 BEGIN_RING(chan, tesla, 0x142c, 1); 413 OUT_RING (chan, 0); 414 return TRUE; 415} 416 417void nv50_so_init_sifc(struct nv50_context *nv50, 418 struct nouveau_stateobj *so, 419 struct nouveau_bo *bo, unsigned reloc, 420 unsigned offset, unsigned size) 421{ 422 struct nouveau_grobj *eng2d = nv50->screen->eng2d; 423 424 reloc |= NOUVEAU_BO_WR; 425 426 so_method(so, eng2d, NV50_2D_DST_FORMAT, 2); 427 so_data (so, NV50_2D_DST_FORMAT_R8_UNORM); 428 so_data (so, 1); 429 so_method(so, eng2d, NV50_2D_DST_PITCH, 5); 430 so_data (so, 262144); 431 so_data (so, 65536); 432 so_data (so, 1); 433 so_reloc (so, bo, offset, reloc | NOUVEAU_BO_HIGH, 0, 0); 434 so_reloc (so, bo, offset, reloc | NOUVEAU_BO_LOW, 0, 0); 435 so_method(so, eng2d, NV50_2D_SIFC_BITMAP_ENABLE, 2); 436 so_data (so, 0); 437 so_data (so, NV50_2D_SIFC_FORMAT_R8_UNORM); 438 so_method(so, eng2d, NV50_2D_SIFC_WIDTH, 10); 439 so_data (so, size); 440 so_data (so, 1); 441 so_data (so, 0); 442 so_data (so, 1); 443 so_data (so, 0); 444 so_data (so, 1); 445 so_data (so, 0); 446 so_data (so, 0); 447 so_data (so, 0); 448 so_data (so, 0); 449} 450