776cecaeb7e870dd817221351e89c2da689a474e
[mesa.git] / src / gallium / drivers / nv50 / nv50_program.c
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 "nv50_program.h"
24 #include "nv50_pc.h"
25 #include "nv50_context.h"
26
27 #include "pipe/p_shader_tokens.h"
28 #include "tgsi/tgsi_parse.h"
29 #include "tgsi/tgsi_util.h"
30 #include "tgsi/tgsi_dump.h"
31
32 #include "codegen/nv50_ir_driver.h"
33
34 static INLINE unsigned
35 bitcount4(const uint32_t val)
36 {
37 static const unsigned cnt[16]
38 = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
39 return cnt[val & 0xf];
40 }
41
42 static unsigned
43 nv50_tgsi_src_mask(const struct tgsi_full_instruction *inst, int c)
44 {
45 unsigned mask = inst->Dst[0].Register.WriteMask;
46
47 switch (inst->Instruction.Opcode) {
48 case TGSI_OPCODE_COS:
49 case TGSI_OPCODE_SIN:
50 return (mask & 0x8) | ((mask & 0x7) ? 0x1 : 0x0);
51 case TGSI_OPCODE_DP3:
52 return 0x7;
53 case TGSI_OPCODE_DP4:
54 case TGSI_OPCODE_DPH:
55 case TGSI_OPCODE_KIL: /* WriteMask ignored */
56 return 0xf;
57 case TGSI_OPCODE_DST:
58 return mask & (c ? 0xa : 0x6);
59 case TGSI_OPCODE_EX2:
60 case TGSI_OPCODE_EXP:
61 case TGSI_OPCODE_LG2:
62 case TGSI_OPCODE_LOG:
63 case TGSI_OPCODE_POW:
64 case TGSI_OPCODE_RCP:
65 case TGSI_OPCODE_RSQ:
66 case TGSI_OPCODE_SCS:
67 return 0x1;
68 case TGSI_OPCODE_IF:
69 return 0x1;
70 case TGSI_OPCODE_LIT:
71 return 0xb;
72 case TGSI_OPCODE_TEX:
73 case TGSI_OPCODE_TXB:
74 case TGSI_OPCODE_TXL:
75 case TGSI_OPCODE_TXP:
76 {
77 const struct tgsi_instruction_texture *tex;
78
79 assert(inst->Instruction.Texture);
80 tex = &inst->Texture;
81
82 mask = 0x7;
83 if (inst->Instruction.Opcode != TGSI_OPCODE_TEX &&
84 inst->Instruction.Opcode != TGSI_OPCODE_TXD)
85 mask |= 0x8; /* bias, lod or proj */
86
87 switch (tex->Texture) {
88 case TGSI_TEXTURE_1D:
89 mask &= 0x9;
90 break;
91 case TGSI_TEXTURE_SHADOW1D:
92 mask &= 0x5;
93 break;
94 case TGSI_TEXTURE_2D:
95 mask &= 0xb;
96 break;
97 default:
98 break;
99 }
100 }
101 return mask;
102 case TGSI_OPCODE_XPD:
103 {
104 unsigned x = 0;
105 if (mask & 1) x |= 0x6;
106 if (mask & 2) x |= 0x5;
107 if (mask & 4) x |= 0x3;
108 return x;
109 }
110 default:
111 break;
112 }
113
114 return mask;
115 }
116
117 static void
118 nv50_indirect_inputs(struct nv50_translation_info *ti, int id)
119 {
120 int i, c;
121
122 for (i = 0; i < PIPE_MAX_SHADER_INPUTS; ++i)
123 for (c = 0; c < 4; ++c)
124 ti->input_access[i][c] = id;
125
126 ti->indirect_inputs = TRUE;
127 }
128
129 static void
130 nv50_indirect_outputs(struct nv50_translation_info *ti, int id)
131 {
132 int i, c;
133
134 for (i = 0; i < PIPE_MAX_SHADER_OUTPUTS; ++i)
135 for (c = 0; c < 4; ++c)
136 ti->output_access[i][c] = id;
137
138 ti->indirect_outputs = TRUE;
139 }
140
141 static void
142 prog_inst(struct nv50_translation_info *ti,
143 const struct tgsi_full_instruction *inst, int id)
144 {
145 const struct tgsi_dst_register *dst;
146 const struct tgsi_src_register *src;
147 int s, c, k;
148 unsigned mask;
149
150 if (inst->Instruction.Opcode == TGSI_OPCODE_BGNSUB) {
151 ti->subr[ti->subr_nr].pos = id - 1;
152 ti->subr[ti->subr_nr].id = ti->subr_nr + 1; /* id 0 is main program */
153 ++ti->subr_nr;
154 }
155
156 if (inst->Dst[0].Register.File == TGSI_FILE_OUTPUT) {
157 dst = &inst->Dst[0].Register;
158
159 for (c = 0; c < 4; ++c) {
160 if (dst->Indirect)
161 nv50_indirect_outputs(ti, id);
162 if (!(dst->WriteMask & (1 << c)))
163 continue;
164 ti->output_access[dst->Index][c] = id;
165 }
166
167 if (inst->Instruction.Opcode == TGSI_OPCODE_MOV &&
168 inst->Src[0].Register.File == TGSI_FILE_INPUT &&
169 dst->Index == ti->edgeflag_out)
170 ti->p->vp.edgeflag = inst->Src[0].Register.Index;
171 } else
172 if (inst->Dst[0].Register.File == TGSI_FILE_TEMPORARY) {
173 if (inst->Dst[0].Register.Indirect)
174 ti->store_to_memory = TRUE;
175 }
176
177 for (s = 0; s < inst->Instruction.NumSrcRegs; ++s) {
178 src = &inst->Src[s].Register;
179 if (src->File == TGSI_FILE_TEMPORARY)
180 if (inst->Src[s].Register.Indirect)
181 ti->store_to_memory = TRUE;
182 if (src->File != TGSI_FILE_INPUT)
183 continue;
184 mask = nv50_tgsi_src_mask(inst, s);
185
186 if (inst->Src[s].Register.Indirect)
187 nv50_indirect_inputs(ti, id);
188
189 for (c = 0; c < 4; ++c) {
190 if (!(mask & (1 << c)))
191 continue;
192 k = tgsi_util_get_full_src_register_swizzle(&inst->Src[s], c);
193 if (k <= TGSI_SWIZZLE_W)
194 ti->input_access[src->Index][k] = id;
195 }
196 }
197 }
198
199 /* Probably should introduce something like struct tgsi_function_declaration
200 * instead of trying to guess inputs/outputs.
201 */
202 static void
203 prog_subroutine_inst(struct nv50_subroutine *subr,
204 const struct tgsi_full_instruction *inst)
205 {
206 const struct tgsi_dst_register *dst;
207 const struct tgsi_src_register *src;
208 int s, c, k;
209 unsigned mask;
210
211 for (s = 0; s < inst->Instruction.NumSrcRegs; ++s) {
212 src = &inst->Src[s].Register;
213 if (src->File != TGSI_FILE_TEMPORARY)
214 continue;
215 mask = nv50_tgsi_src_mask(inst, s);
216
217 assert(!inst->Src[s].Register.Indirect);
218
219 for (c = 0; c < 4; ++c) {
220 k = tgsi_util_get_full_src_register_swizzle(&inst->Src[s], c);
221
222 if ((mask & (1 << c)) && k < TGSI_SWIZZLE_W)
223 if (!(subr->retv[src->Index / 32][k] & (1 << (src->Index % 32))))
224 subr->argv[src->Index / 32][k] |= 1 << (src->Index % 32);
225 }
226 }
227
228 if (inst->Dst[0].Register.File == TGSI_FILE_TEMPORARY) {
229 dst = &inst->Dst[0].Register;
230
231 for (c = 0; c < 4; ++c)
232 if (dst->WriteMask & (1 << c))
233 subr->retv[dst->Index / 32][c] |= 1 << (dst->Index % 32);
234 }
235 }
236
237 static void
238 prog_immediate(struct nv50_translation_info *ti,
239 const struct tgsi_full_immediate *imm)
240 {
241 int c;
242 unsigned n = ti->immd32_nr++;
243
244 assert(ti->immd32_nr <= ti->scan.immediate_count);
245
246 for (c = 0; c < 4; ++c)
247 ti->immd32[n * 4 + c] = imm->u[c].Uint;
248
249 ti->immd32_ty[n] = imm->Immediate.DataType;
250 }
251
252 static INLINE unsigned
253 translate_interpolate(const struct tgsi_full_declaration *decl)
254 {
255 unsigned mode;
256
257 if (decl->Declaration.Interpolate == TGSI_INTERPOLATE_CONSTANT)
258 mode = NV50_INTERP_FLAT;
259 else
260 if (decl->Declaration.Interpolate == TGSI_INTERPOLATE_PERSPECTIVE)
261 mode = 0;
262 else
263 mode = NV50_INTERP_LINEAR;
264
265 if (decl->Declaration.Centroid)
266 mode |= NV50_INTERP_CENTROID;
267
268 return mode;
269 }
270
271 static void
272 prog_decl(struct nv50_translation_info *ti,
273 const struct tgsi_full_declaration *decl)
274 {
275 unsigned i, first, last, sn = 0, si = 0;
276
277 first = decl->Range.First;
278 last = decl->Range.Last;
279
280 if (decl->Declaration.Semantic) {
281 sn = decl->Semantic.Name;
282 si = decl->Semantic.Index;
283 }
284
285 switch (decl->Declaration.File) {
286 case TGSI_FILE_INPUT:
287 for (i = first; i <= last; ++i)
288 ti->interp_mode[i] = translate_interpolate(decl);
289
290 if (!decl->Declaration.Semantic)
291 break;
292
293 for (i = first; i <= last; ++i) {
294 ti->p->in[i].sn = sn;
295 ti->p->in[i].si = si;
296 }
297
298 switch (sn) {
299 case TGSI_SEMANTIC_FACE:
300 break;
301 case TGSI_SEMANTIC_COLOR:
302 if (ti->p->type == PIPE_SHADER_FRAGMENT)
303 ti->p->vp.bfc[si] = first;
304 break;
305 }
306 break;
307 case TGSI_FILE_OUTPUT:
308 if (!decl->Declaration.Semantic)
309 break;
310
311 for (i = first; i <= last; ++i) {
312 ti->p->out[i].sn = sn;
313 ti->p->out[i].si = si;
314 }
315
316 switch (sn) {
317 case TGSI_SEMANTIC_BCOLOR:
318 ti->p->vp.bfc[si] = first;
319 break;
320 case TGSI_SEMANTIC_PSIZE:
321 ti->p->vp.psiz = first;
322 break;
323 case TGSI_SEMANTIC_EDGEFLAG:
324 ti->edgeflag_out = first;
325 break;
326 default:
327 break;
328 }
329 break;
330 case TGSI_FILE_SYSTEM_VALUE:
331 /* For VP/GP inputs, they are put in s[] after the last normal input.
332 * Let sysval_map reflect the order of the sysvals in s[] and fixup later.
333 */
334 switch (decl->Semantic.Name) {
335 case TGSI_SEMANTIC_FACE:
336 break;
337 case TGSI_SEMANTIC_INSTANCEID:
338 ti->p->vp.attrs[2] |= NV50_3D_VP_GP_BUILTIN_ATTR_EN_INSTANCE_ID;
339 ti->sysval_map[first] = 2;
340 break;
341 case TGSI_SEMANTIC_PRIMID:
342 break;
343 /*
344 case TGSI_SEMANTIC_PRIMIDIN:
345 break;
346 case TGSI_SEMANTIC_VERTEXID:
347 break;
348 */
349 default:
350 break;
351 }
352 break;
353 case TGSI_FILE_CONSTANT:
354 ti->p->parm_size = MAX2(ti->p->parm_size, (last + 1) * 16);
355 break;
356 case TGSI_FILE_ADDRESS:
357 case TGSI_FILE_SAMPLER:
358 case TGSI_FILE_TEMPORARY:
359 break;
360 default:
361 assert(0);
362 break;
363 }
364 }
365
366 static int
367 nv50_vertprog_prepare(struct nv50_translation_info *ti)
368 {
369 struct nv50_program *p = ti->p;
370 int i, c;
371 unsigned num_inputs = 0;
372
373 ti->input_file = NV_FILE_MEM_S;
374 ti->output_file = NV_FILE_OUT;
375
376 for (i = 0; i <= ti->scan.file_max[TGSI_FILE_INPUT]; ++i) {
377 p->in[i].id = i;
378 p->in[i].hw = num_inputs;
379
380 for (c = 0; c < 4; ++c) {
381 if (!ti->input_access[i][c])
382 continue;
383 ti->input_map[i][c] = num_inputs++;
384 p->vp.attrs[(4 * i + c) / 32] |= 1 << ((i * 4 + c) % 32);
385 }
386 }
387
388 for (i = 0; i <= ti->scan.file_max[TGSI_FILE_OUTPUT]; ++i) {
389 p->out[i].id = i;
390 p->out[i].hw = p->max_out;
391
392 for (c = 0; c < 4; ++c) {
393 if (!ti->output_access[i][c])
394 continue;
395 ti->output_map[i][c] = p->max_out++;
396 p->out[i].mask |= 1 << c;
397 }
398 }
399
400 p->vp.clpd = p->max_out;
401 p->max_out += p->vp.clpd_nr;
402
403 for (i = 0; i < TGSI_SEMANTIC_COUNT; ++i) {
404 switch (ti->sysval_map[i]) {
405 case 2:
406 if (!(ti->p->vp.attrs[2] & NV50_3D_VP_GP_BUILTIN_ATTR_EN_VERTEX_ID))
407 ti->sysval_map[i] = 1;
408 ti->sysval_map[i] = (ti->sysval_map[i] - 1) + num_inputs;
409 break;
410 default:
411 break;
412 }
413 }
414
415 if (p->vp.psiz < 0x40)
416 p->vp.psiz = p->out[p->vp.psiz].hw;
417
418 return 0;
419 }
420
421 static int
422 nv50_fragprog_prepare(struct nv50_translation_info *ti)
423 {
424 struct nv50_program *p = ti->p;
425 int i, j, c;
426 unsigned nvary, nintp, depr;
427 unsigned n = 0, m = 0, skip = 0;
428 ubyte sn[16], si[16];
429
430 /* FP flags */
431
432 if (ti->scan.writes_z) {
433 p->fp.flags[1] = 0x11;
434 p->fp.flags[0] |= NV50_3D_FP_CONTROL_EXPORTS_Z;
435 }
436
437 if (ti->scan.uses_kill)
438 p->fp.flags[0] |= NV50_3D_FP_CONTROL_USES_KIL;
439
440 /* FP inputs */
441
442 ti->input_file = NV_FILE_MEM_V;
443 ti->output_file = NV_FILE_GPR;
444
445 /* count non-flat inputs, save semantic info */
446 for (i = 0; i < p->in_nr; ++i) {
447 m += (ti->interp_mode[i] & NV50_INTERP_FLAT) ? 0 : 1;
448 sn[i] = p->in[i].sn;
449 si[i] = p->in[i].si;
450 }
451
452 /* reorder p->in[] so that non-flat inputs are first and
453 * kick out special inputs that don't use VP/GP_RESULT_MAP
454 */
455 nintp = 0;
456 for (i = 0; i < p->in_nr; ++i) {
457 if (sn[i] == TGSI_SEMANTIC_POSITION) {
458 for (c = 0; c < 4; ++c) {
459 ti->input_map[i][c] = nintp;
460 if (ti->input_access[i][c]) {
461 p->fp.interp |= 1 << (24 + c);
462 ++nintp;
463 }
464 }
465 skip++;
466 continue;
467 } else
468 if (sn[i] == TGSI_SEMANTIC_FACE) {
469 ti->input_map[i][0] = 255;
470 skip++;
471 continue;
472 }
473
474 j = (ti->interp_mode[i] & NV50_INTERP_FLAT) ? m++ : n++;
475
476 if (sn[i] == TGSI_SEMANTIC_COLOR)
477 p->vp.bfc[si[i]] = j;
478
479 p->in[j].linear = (ti->interp_mode[i] & NV50_INTERP_LINEAR) ? 1 : 0;
480 p->in[j].id = i;
481 p->in[j].sn = sn[i];
482 p->in[j].si = si[i];
483 }
484 assert(n <= m);
485 p->in_nr -= skip;
486
487 if (!(p->fp.interp & (8 << 24))) {
488 p->fp.interp |= (8 << 24);
489 ++nintp;
490 }
491
492 /* after HPOS */
493 p->fp.colors = 4 << NV50_3D_SEMANTIC_COLOR_FFC0_ID__SHIFT;
494
495 for (i = 0; i < p->in_nr; ++i) {
496 int j = p->in[i].id;
497 p->in[i].hw = nintp;
498
499 for (c = 0; c < 4; ++c) {
500 if (!ti->input_access[j][c])
501 continue;
502 p->in[i].mask |= 1 << c;
503 ti->input_map[j][c] = nintp++;
504 }
505 /* count color inputs */
506 if (i == p->vp.bfc[0] || i == p->vp.bfc[1])
507 p->fp.colors += bitcount4(p->in[i].mask) << 16;
508 }
509 nintp -= bitcount4(p->fp.interp >> 24); /* subtract position inputs */
510 nvary = nintp;
511 if (n < m)
512 nvary -= p->in[n].hw;
513
514 p->fp.interp |= nvary << NV50_3D_FP_INTERPOLANT_CTRL_COUNT_NONFLAT__SHIFT;
515 p->fp.interp |= nintp << NV50_3D_FP_INTERPOLANT_CTRL_COUNT__SHIFT;
516
517 /* FP outputs */
518
519 if (p->out_nr > (1 + (ti->scan.writes_z ? 1 : 0)))
520 p->fp.flags[0] |= NV50_3D_FP_CONTROL_MULTIPLE_RESULTS;
521
522 depr = p->out_nr;
523 for (i = 0; i < p->out_nr; ++i) {
524 p->out[i].id = i;
525 if (p->out[i].sn == TGSI_SEMANTIC_POSITION) {
526 depr = i;
527 continue;
528 }
529 p->out[i].hw = p->max_out;
530 p->out[i].mask = 0xf;
531
532 for (c = 0; c < 4; ++c)
533 ti->output_map[i][c] = p->max_out++;
534 }
535 if (depr < p->out_nr) {
536 p->out[depr].mask = 0x4;
537 p->out[depr].hw = ti->output_map[depr][2] = p->max_out++;
538 } else {
539 /* allowed values are 1, 4, 5, 8, 9, ... */
540 p->max_out = MAX2(4, p->max_out);
541 }
542
543 return 0;
544 }
545
546 static int
547 nv50_geomprog_prepare(struct nv50_translation_info *ti)
548 {
549 ti->input_file = NV_FILE_MEM_S;
550 ti->output_file = NV_FILE_OUT;
551
552 assert(0);
553 return 1;
554 }
555
556 static int
557 nv50_prog_scan(struct nv50_translation_info *ti)
558 {
559 struct nv50_program *p = ti->p;
560 struct tgsi_parse_context parse;
561 int ret, i;
562
563 p->vp.edgeflag = 0x40;
564 p->vp.psiz = 0x40;
565 p->vp.bfc[0] = 0x40;
566 p->vp.bfc[1] = 0x40;
567 p->gp.primid = 0x80;
568
569 tgsi_scan_shader(p->pipe.tokens, &ti->scan);
570
571 #if NV50_DEBUG & NV50_DEBUG_SHADER
572 tgsi_dump(p->pipe.tokens, 0);
573 #endif
574
575 ti->subr =
576 CALLOC(ti->scan.opcode_count[TGSI_OPCODE_BGNSUB], sizeof(ti->subr[0]));
577
578 ti->immd32 = (uint32_t *)MALLOC(ti->scan.immediate_count * 16);
579 ti->immd32_ty = (ubyte *)MALLOC(ti->scan.immediate_count * sizeof(ubyte));
580
581 ti->insns = MALLOC(ti->scan.num_instructions * sizeof(ti->insns[0]));
582
583 tgsi_parse_init(&parse, p->pipe.tokens);
584 while (!tgsi_parse_end_of_tokens(&parse)) {
585 tgsi_parse_token(&parse);
586
587 switch (parse.FullToken.Token.Type) {
588 case TGSI_TOKEN_TYPE_IMMEDIATE:
589 prog_immediate(ti, &parse.FullToken.FullImmediate);
590 break;
591 case TGSI_TOKEN_TYPE_DECLARATION:
592 prog_decl(ti, &parse.FullToken.FullDeclaration);
593 break;
594 case TGSI_TOKEN_TYPE_INSTRUCTION:
595 ti->insns[ti->inst_nr] = parse.FullToken.FullInstruction;
596 prog_inst(ti, &parse.FullToken.FullInstruction, ++ti->inst_nr);
597 break;
598 }
599 }
600
601 /* Scan to determine which registers are inputs/outputs of a subroutine. */
602 for (i = 0; i < ti->subr_nr; ++i) {
603 int pc = ti->subr[i].id;
604 while (ti->insns[pc].Instruction.Opcode != TGSI_OPCODE_ENDSUB)
605 prog_subroutine_inst(&ti->subr[i], &ti->insns[pc++]);
606 }
607
608 p->in_nr = ti->scan.file_max[TGSI_FILE_INPUT] + 1;
609 p->out_nr = ti->scan.file_max[TGSI_FILE_OUTPUT] + 1;
610
611 switch (p->type) {
612 case PIPE_SHADER_VERTEX:
613 ret = nv50_vertprog_prepare(ti);
614 break;
615 case PIPE_SHADER_FRAGMENT:
616 ret = nv50_fragprog_prepare(ti);
617 break;
618 case PIPE_SHADER_GEOMETRY:
619 ret = nv50_geomprog_prepare(ti);
620 break;
621 default:
622 assert(!"unsupported program type");
623 ret = -1;
624 break;
625 }
626
627 assert(!ret);
628 return ret;
629 }
630
631 /* Temporary, need a reference to nv50_ir_generate_code in libnv50 or
632 * it "gets disappeared" and cannot be used in libnvc0 ...
633 */
634 boolean
635 nv50_program_translate_new(struct nv50_program *p)
636 {
637 struct nv50_ir_prog_info info;
638
639 return nv50_ir_generate_code(&info);
640 }
641
642 boolean
643 nv50_program_translate(struct nv50_program *p)
644 {
645 struct nv50_translation_info *ti;
646 int ret;
647
648 ti = CALLOC_STRUCT(nv50_translation_info);
649 ti->p = p;
650
651 ti->edgeflag_out = PIPE_MAX_SHADER_OUTPUTS;
652
653 ret = nv50_prog_scan(ti);
654 if (ret) {
655 NOUVEAU_ERR("unsupported shader program\n");
656 goto out;
657 }
658
659 ret = nv50_generate_code(ti);
660 if (ret) {
661 NOUVEAU_ERR("error during shader translation\n");
662 goto out;
663 }
664
665 out:
666 if (ti->immd32)
667 FREE(ti->immd32);
668 if (ti->immd32_ty)
669 FREE(ti->immd32_ty);
670 if (ti->insns)
671 FREE(ti->insns);
672 if (ti->subr)
673 FREE(ti->subr);
674 FREE(ti);
675 return ret ? FALSE : TRUE;
676 }
677
678 void
679 nv50_program_destroy(struct nv50_context *nv50, struct nv50_program *p)
680 {
681 const struct pipe_shader_state pipe = p->pipe;
682 const ubyte type = p->type;
683
684 if (p->mem)
685 nouveau_heap_free(&p->mem);
686
687 if (p->code)
688 FREE(p->code);
689
690 if (p->fixups)
691 FREE(p->fixups);
692
693 memset(p, 0, sizeof(*p));
694
695 p->pipe = pipe;
696 p->type = type;
697 }