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