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 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 "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_context.h" 29 30 static INLINE void 31 nvc0_program_update_context_state(struct nvc0_context *nvc0, 32 struct nvc0_program *prog, int stage) 33 { 34 struct nouveau_pushbuf *push = nvc0->base.pushbuf; 35 36 if (prog && prog->need_tls) { 37 const uint32_t flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_RDWR; 38 if (!nvc0->state.tls_required) 39 BCTX_REFN_bo(nvc0->bufctx_3d, TLS, flags, nvc0->screen->tls); 40 nvc0->state.tls_required |= 1 << stage; 41 } else { 42 if (nvc0->state.tls_required == (1 << stage)) 43 nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_TLS); 44 nvc0->state.tls_required &= ~(1 << stage); 45 } 46 47 if (prog && prog->immd_size) { 48 BEGIN_NVC0(push, NVC0_3D(CB_SIZE), 3); 49 /* NOTE: may overlap code of a different shader */ 50 PUSH_DATA (push, align(prog->immd_size, 0x100)); 51 PUSH_DATAh(push, nvc0->screen->text->offset + prog->immd_base); 52 PUSH_DATA (push, nvc0->screen->text->offset + prog->immd_base); 53 BEGIN_NVC0(push, NVC0_3D(CB_BIND(stage)), 1); 54 PUSH_DATA (push, (14 << 4) | 1); 55 56 nvc0->state.c14_bound |= 1 << stage; 57 } else 58 if (nvc0->state.c14_bound & (1 << stage)) { 59 BEGIN_NVC0(push, NVC0_3D(CB_BIND(stage)), 1); 60 PUSH_DATA (push, (14 << 4) | 0); 61 62 nvc0->state.c14_bound &= ~(1 << stage); 63 } 64 } 65 66 static INLINE boolean 67 nvc0_program_validate(struct nvc0_context *nvc0, struct nvc0_program *prog) 68 { 69 if (prog->mem) 70 return TRUE; 71 72 if (!prog->translated) { 73 prog->translated = nvc0_program_translate( 74 prog, nvc0->screen->base.device->chipset); 75 if (!prog->translated) 76 return FALSE; 77 } 78 79 if (likely(prog->code_size)) 80 return nvc0_program_upload_code(nvc0, prog); 81 return TRUE; /* stream output info only */ 82 } 83 84 void 85 nvc0_vertprog_validate(struct nvc0_context *nvc0) 86 { 87 struct nouveau_pushbuf *push = nvc0->base.pushbuf; 88 struct nvc0_program *vp = nvc0->vertprog; 89 90 if (!nvc0_program_validate(nvc0, vp)) 91 return; 92 nvc0_program_update_context_state(nvc0, vp, 0); 93 94 BEGIN_NVC0(push, NVC0_3D(SP_SELECT(1)), 2); 95 PUSH_DATA (push, 0x11); 96 PUSH_DATA (push, vp->code_base); 97 BEGIN_NVC0(push, NVC0_3D(SP_GPR_ALLOC(1)), 1); 98 PUSH_DATA (push, vp->max_gpr); 99 100 // BEGIN_NVC0(push, NVC0_3D_(0x163c), 1); 101 // PUSH_DATA (push, 0); 102 } 103 104 void 105 nvc0_fragprog_validate(struct nvc0_context *nvc0) 106 { 107 struct nouveau_pushbuf *push = nvc0->base.pushbuf; 108 struct nvc0_program *fp = nvc0->fragprog; 109 110 if (!nvc0_program_validate(nvc0, fp)) 111 return; 112 nvc0_program_update_context_state(nvc0, fp, 4); 113 114 if (fp->fp.early_z != nvc0->state.early_z_forced) { 115 nvc0->state.early_z_forced = fp->fp.early_z; 116 IMMED_NVC0(push, NVC0_3D(FORCE_EARLY_FRAGMENT_TESTS), fp->fp.early_z); 117 } 118 119 BEGIN_NVC0(push, NVC0_3D(SP_SELECT(5)), 2); 120 PUSH_DATA (push, 0x51); 121 PUSH_DATA (push, fp->code_base); 122 BEGIN_NVC0(push, NVC0_3D(SP_GPR_ALLOC(5)), 1); 123 PUSH_DATA (push, fp->max_gpr); 124 125 BEGIN_NVC0(push, SUBC_3D(0x0360), 2); 126 PUSH_DATA (push, 0x20164010); 127 PUSH_DATA (push, 0x20); 128 BEGIN_NVC0(push, NVC0_3D(ZCULL_TEST_MASK), 1); 129 PUSH_DATA (push, fp->flags[0]); 130 } 131 132 void 133 nvc0_tctlprog_validate(struct nvc0_context *nvc0) 134 { 135 struct nouveau_pushbuf *push = nvc0->base.pushbuf; 136 struct nvc0_program *tp = nvc0->tctlprog; 137 138 if (tp && nvc0_program_validate(nvc0, tp)) { 139 if (tp->tp.tess_mode != ~0) { 140 BEGIN_NVC0(push, NVC0_3D(TESS_MODE), 1); 141 PUSH_DATA (push, tp->tp.tess_mode); 142 } 143 BEGIN_NVC0(push, NVC0_3D(SP_SELECT(2)), 2); 144 PUSH_DATA (push, 0x21); 145 PUSH_DATA (push, tp->code_base); 146 BEGIN_NVC0(push, NVC0_3D(SP_GPR_ALLOC(2)), 1); 147 PUSH_DATA (push, tp->max_gpr); 148 149 if (tp->tp.input_patch_size <= 32) 150 IMMED_NVC0(push, NVC0_3D(PATCH_VERTICES), tp->tp.input_patch_size); 151 } else { 152 BEGIN_NVC0(push, NVC0_3D(SP_SELECT(2)), 1); 153 PUSH_DATA (push, 0x20); 154 } 155 nvc0_program_update_context_state(nvc0, tp, 1); 156 } 157 158 void 159 nvc0_tevlprog_validate(struct nvc0_context *nvc0) 160 { 161 struct nouveau_pushbuf *push = nvc0->base.pushbuf; 162 struct nvc0_program *tp = nvc0->tevlprog; 163 164 if (tp && nvc0_program_validate(nvc0, tp)) { 165 if (tp->tp.tess_mode != ~0) { 166 BEGIN_NVC0(push, NVC0_3D(TESS_MODE), 1); 167 PUSH_DATA (push, tp->tp.tess_mode); 168 } 169 BEGIN_NVC0(push, NVC0_3D(MACRO_TEP_SELECT), 1); 170 PUSH_DATA (push, 0x31); 171 BEGIN_NVC0(push, NVC0_3D(SP_START_ID(3)), 1); 172 PUSH_DATA (push, tp->code_base); 173 BEGIN_NVC0(push, NVC0_3D(SP_GPR_ALLOC(3)), 1); 174 PUSH_DATA (push, tp->max_gpr); 175 } else { 176 BEGIN_NVC0(push, NVC0_3D(MACRO_TEP_SELECT), 1); 177 PUSH_DATA (push, 0x30); 178 } 179 nvc0_program_update_context_state(nvc0, tp, 2); 180 } 181 182 void 183 nvc0_gmtyprog_validate(struct nvc0_context *nvc0) 184 { 185 struct nouveau_pushbuf *push = nvc0->base.pushbuf; 186 struct nvc0_program *gp = nvc0->gmtyprog; 187 188 if (gp) 189 nvc0_program_validate(nvc0, gp); 190 191 /* we allow GPs with no code for specifying stream output state only */ 192 if (gp && gp->code_size) { 193 const boolean gp_selects_layer = gp->hdr[13] & (1 << 9); 194 195 BEGIN_NVC0(push, NVC0_3D(MACRO_GP_SELECT), 1); 196 PUSH_DATA (push, 0x41); 197 BEGIN_NVC0(push, NVC0_3D(SP_START_ID(4)), 1); 198 PUSH_DATA (push, gp->code_base); 199 BEGIN_NVC0(push, NVC0_3D(SP_GPR_ALLOC(4)), 1); 200 PUSH_DATA (push, gp->max_gpr); 201 BEGIN_NVC0(push, NVC0_3D(LAYER), 1); 202 PUSH_DATA (push, gp_selects_layer ? NVC0_3D_LAYER_USE_GP : 0); 203 } else { 204 IMMED_NVC0(push, NVC0_3D(LAYER), 0); 205 BEGIN_NVC0(push, NVC0_3D(MACRO_GP_SELECT), 1); 206 PUSH_DATA (push, 0x40); 207 } 208 nvc0_program_update_context_state(nvc0, gp, 3); 209 } 210 211 void 212 nvc0_tfb_validate(struct nvc0_context *nvc0) 213 { 214 struct nouveau_pushbuf *push = nvc0->base.pushbuf; 215 struct nvc0_transform_feedback_state *tfb; 216 unsigned b; 217 218 if (nvc0->gmtyprog) tfb = nvc0->gmtyprog->tfb; 219 else 220 if (nvc0->tevlprog) tfb = nvc0->tevlprog->tfb; 221 else 222 tfb = nvc0->vertprog->tfb; 223 224 IMMED_NVC0(push, NVC0_3D(TFB_ENABLE), (tfb && nvc0->num_tfbbufs) ? 1 : 0); 225 226 if (tfb && tfb != nvc0->state.tfb) { 227 for (b = 0; b < 4; ++b) { 228 if (tfb->varying_count[b]) { 229 unsigned n = (tfb->varying_count[b] + 3) / 4; 230 231 BEGIN_NVC0(push, NVC0_3D(TFB_STREAM(b)), 3); 232 PUSH_DATA (push, 0); 233 PUSH_DATA (push, tfb->varying_count[b]); 234 PUSH_DATA (push, tfb->stride[b]); 235 BEGIN_NVC0(push, NVC0_3D(TFB_VARYING_LOCS(b, 0)), n); 236 PUSH_DATAp(push, tfb->varying_index[b], n); 237 238 if (nvc0->tfbbuf[b]) 239 nvc0_so_target(nvc0->tfbbuf[b])->stride = tfb->stride[b]; 240 } else { 241 IMMED_NVC0(push, NVC0_3D(TFB_VARYING_COUNT(b)), 0); 242 } 243 } 244 } 245 nvc0->state.tfb = tfb; 246 247 if (!(nvc0->dirty & NVC0_NEW_TFB_TARGETS)) 248 return; 249 nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_TFB); 250 251 for (b = 0; b < nvc0->num_tfbbufs; ++b) { 252 struct nvc0_so_target *targ = nvc0_so_target(nvc0->tfbbuf[b]); 253 struct nv04_resource *buf = nv04_resource(targ->pipe.buffer); 254 255 if (tfb) 256 targ->stride = tfb->stride[b]; 257 258 if (!(nvc0->tfbbuf_dirty & (1 << b))) 259 continue; 260 261 if (!targ->clean) 262 nvc0_query_fifo_wait(push, targ->pq); 263 BEGIN_NVC0(push, NVC0_3D(TFB_BUFFER_ENABLE(b)), 5); 264 PUSH_DATA (push, 1); 265 PUSH_DATAh(push, buf->address + targ->pipe.buffer_offset); 266 PUSH_DATA (push, buf->address + targ->pipe.buffer_offset); 267 PUSH_DATA (push, targ->pipe.buffer_size); 268 if (!targ->clean) { 269 nvc0_query_pushbuf_submit(push, targ->pq, 0x4); 270 } else { 271 PUSH_DATA(push, 0); /* TFB_BUFFER_OFFSET */ 272 targ->clean = FALSE; 273 } 274 BCTX_REFN(nvc0->bufctx_3d, TFB, buf, WR); 275 } 276 for (; b < 4; ++b) 277 IMMED_NVC0(push, NVC0_3D(TFB_BUFFER_ENABLE(b)), 0); 278 } 279