Drop GLcontext typedef and use struct gl_context instead
[mesa.git] / src / mesa / program / program.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5.3
4 *
5 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25 /**
26 * \file program.c
27 * Vertex and fragment program support functions.
28 * \author Brian Paul
29 */
30
31
32 #include "main/glheader.h"
33 #include "main/context.h"
34 #include "main/hash.h"
35 #include "program.h"
36 #include "prog_cache.h"
37 #include "prog_parameter.h"
38 #include "prog_instruction.h"
39
40
41 /**
42 * A pointer to this dummy program is put into the hash table when
43 * glGenPrograms is called.
44 */
45 struct gl_program _mesa_DummyProgram;
46
47
48 /**
49 * Init context's vertex/fragment program state
50 */
51 void
52 _mesa_init_program(struct gl_context *ctx)
53 {
54 GLuint i;
55
56 /*
57 * If this assertion fails, we need to increase the field
58 * size for register indexes (see INST_INDEX_BITS).
59 */
60 ASSERT(ctx->Const.VertexProgram.MaxUniformComponents / 4
61 <= (1 << INST_INDEX_BITS));
62 ASSERT(ctx->Const.FragmentProgram.MaxUniformComponents / 4
63 <= (1 << INST_INDEX_BITS));
64
65 ASSERT(ctx->Const.VertexProgram.MaxTemps <= (1 << INST_INDEX_BITS));
66 ASSERT(ctx->Const.VertexProgram.MaxLocalParams <= (1 << INST_INDEX_BITS));
67 ASSERT(ctx->Const.FragmentProgram.MaxTemps <= (1 << INST_INDEX_BITS));
68 ASSERT(ctx->Const.FragmentProgram.MaxLocalParams <= (1 << INST_INDEX_BITS));
69
70 ASSERT(ctx->Const.VertexProgram.MaxUniformComponents <= 4 * MAX_UNIFORMS);
71 ASSERT(ctx->Const.FragmentProgram.MaxUniformComponents <= 4 * MAX_UNIFORMS);
72
73 /* If this fails, increase prog_instruction::TexSrcUnit size */
74 ASSERT(MAX_TEXTURE_UNITS < (1 << 5));
75
76 /* If this fails, increase prog_instruction::TexSrcTarget size */
77 ASSERT(NUM_TEXTURE_TARGETS < (1 << 3));
78
79 ctx->Program.ErrorPos = -1;
80 ctx->Program.ErrorString = _mesa_strdup("");
81
82 #if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program
83 ctx->VertexProgram.Enabled = GL_FALSE;
84 #if FEATURE_es2_glsl
85 ctx->VertexProgram.PointSizeEnabled =
86 (ctx->API == API_OPENGLES2) ? GL_TRUE : GL_FALSE;
87 #else
88 ctx->VertexProgram.PointSizeEnabled = GL_FALSE;
89 #endif
90 ctx->VertexProgram.TwoSideEnabled = GL_FALSE;
91 _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current,
92 ctx->Shared->DefaultVertexProgram);
93 assert(ctx->VertexProgram.Current);
94 for (i = 0; i < MAX_NV_VERTEX_PROGRAM_PARAMS / 4; i++) {
95 ctx->VertexProgram.TrackMatrix[i] = GL_NONE;
96 ctx->VertexProgram.TrackMatrixTransform[i] = GL_IDENTITY_NV;
97 }
98 ctx->VertexProgram.Cache = _mesa_new_program_cache();
99 #endif
100
101 #if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program
102 ctx->FragmentProgram.Enabled = GL_FALSE;
103 _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current,
104 ctx->Shared->DefaultFragmentProgram);
105 assert(ctx->FragmentProgram.Current);
106 ctx->FragmentProgram.Cache = _mesa_new_program_cache();
107 #endif
108
109 #if FEATURE_ARB_geometry_shader4
110 ctx->GeometryProgram.Enabled = GL_FALSE;
111 /* right now by default we don't have a geometry program */
112 _mesa_reference_geomprog(ctx, &ctx->GeometryProgram.Current,
113 NULL);
114 ctx->GeometryProgram.Cache = _mesa_new_program_cache();
115 #endif
116
117 /* XXX probably move this stuff */
118 #if FEATURE_ATI_fragment_shader
119 ctx->ATIFragmentShader.Enabled = GL_FALSE;
120 ctx->ATIFragmentShader.Current = ctx->Shared->DefaultFragmentShader;
121 assert(ctx->ATIFragmentShader.Current);
122 ctx->ATIFragmentShader.Current->RefCount++;
123 #endif
124 }
125
126
127 /**
128 * Free a context's vertex/fragment program state
129 */
130 void
131 _mesa_free_program_data(struct gl_context *ctx)
132 {
133 #if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program
134 _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, NULL);
135 _mesa_delete_program_cache(ctx, ctx->VertexProgram.Cache);
136 #endif
137 #if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program
138 _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, NULL);
139 _mesa_delete_program_cache(ctx, ctx->FragmentProgram.Cache);
140 #endif
141 #if FEATURE_ARB_geometry_shader4
142 _mesa_reference_geomprog(ctx, &ctx->GeometryProgram.Current, NULL);
143 _mesa_delete_program_cache(ctx, ctx->GeometryProgram.Cache);
144 #endif
145 /* XXX probably move this stuff */
146 #if FEATURE_ATI_fragment_shader
147 if (ctx->ATIFragmentShader.Current) {
148 ctx->ATIFragmentShader.Current->RefCount--;
149 if (ctx->ATIFragmentShader.Current->RefCount <= 0) {
150 free(ctx->ATIFragmentShader.Current);
151 }
152 }
153 #endif
154 free((void *) ctx->Program.ErrorString);
155 }
156
157
158 /**
159 * Update the default program objects in the given context to reference those
160 * specified in the shared state and release those referencing the old
161 * shared state.
162 */
163 void
164 _mesa_update_default_objects_program(struct gl_context *ctx)
165 {
166 #if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program
167 _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current,
168 (struct gl_vertex_program *)
169 ctx->Shared->DefaultVertexProgram);
170 assert(ctx->VertexProgram.Current);
171 #endif
172
173 #if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program
174 _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current,
175 (struct gl_fragment_program *)
176 ctx->Shared->DefaultFragmentProgram);
177 assert(ctx->FragmentProgram.Current);
178 #endif
179
180 #if FEATURE_ARB_geometry_shader4
181 _mesa_reference_geomprog(ctx, &ctx->GeometryProgram.Current,
182 (struct gl_geometry_program *)
183 ctx->Shared->DefaultGeometryProgram);
184 #endif
185
186 /* XXX probably move this stuff */
187 #if FEATURE_ATI_fragment_shader
188 if (ctx->ATIFragmentShader.Current) {
189 ctx->ATIFragmentShader.Current->RefCount--;
190 if (ctx->ATIFragmentShader.Current->RefCount <= 0) {
191 free(ctx->ATIFragmentShader.Current);
192 }
193 }
194 ctx->ATIFragmentShader.Current = (struct ati_fragment_shader *) ctx->Shared->DefaultFragmentShader;
195 assert(ctx->ATIFragmentShader.Current);
196 ctx->ATIFragmentShader.Current->RefCount++;
197 #endif
198 }
199
200
201 /**
202 * Set the vertex/fragment program error state (position and error string).
203 * This is generally called from within the parsers.
204 */
205 void
206 _mesa_set_program_error(struct gl_context *ctx, GLint pos, const char *string)
207 {
208 ctx->Program.ErrorPos = pos;
209 free((void *) ctx->Program.ErrorString);
210 if (!string)
211 string = "";
212 ctx->Program.ErrorString = _mesa_strdup(string);
213 }
214
215
216 /**
217 * Find the line number and column for 'pos' within 'string'.
218 * Return a copy of the line which contains 'pos'. Free the line with
219 * free().
220 * \param string the program string
221 * \param pos the position within the string
222 * \param line returns the line number corresponding to 'pos'.
223 * \param col returns the column number corresponding to 'pos'.
224 * \return copy of the line containing 'pos'.
225 */
226 const GLubyte *
227 _mesa_find_line_column(const GLubyte *string, const GLubyte *pos,
228 GLint *line, GLint *col)
229 {
230 const GLubyte *lineStart = string;
231 const GLubyte *p = string;
232 GLubyte *s;
233 int len;
234
235 *line = 1;
236
237 while (p != pos) {
238 if (*p == (GLubyte) '\n') {
239 (*line)++;
240 lineStart = p + 1;
241 }
242 p++;
243 }
244
245 *col = (pos - lineStart) + 1;
246
247 /* return copy of this line */
248 while (*p != 0 && *p != '\n')
249 p++;
250 len = p - lineStart;
251 s = (GLubyte *) malloc(len + 1);
252 memcpy(s, lineStart, len);
253 s[len] = 0;
254
255 return s;
256 }
257
258
259 /**
260 * Initialize a new vertex/fragment program object.
261 */
262 static struct gl_program *
263 _mesa_init_program_struct( struct gl_context *ctx, struct gl_program *prog,
264 GLenum target, GLuint id)
265 {
266 (void) ctx;
267 if (prog) {
268 GLuint i;
269 memset(prog, 0, sizeof(*prog));
270 prog->Id = id;
271 prog->Target = target;
272 prog->Resident = GL_TRUE;
273 prog->RefCount = 1;
274 prog->Format = GL_PROGRAM_FORMAT_ASCII_ARB;
275
276 /* default mapping from samplers to texture units */
277 for (i = 0; i < MAX_SAMPLERS; i++)
278 prog->SamplerUnits[i] = i;
279 }
280
281 return prog;
282 }
283
284
285 /**
286 * Initialize a new fragment program object.
287 */
288 struct gl_program *
289 _mesa_init_fragment_program( struct gl_context *ctx, struct gl_fragment_program *prog,
290 GLenum target, GLuint id)
291 {
292 if (prog)
293 return _mesa_init_program_struct( ctx, &prog->Base, target, id );
294 else
295 return NULL;
296 }
297
298
299 /**
300 * Initialize a new vertex program object.
301 */
302 struct gl_program *
303 _mesa_init_vertex_program( struct gl_context *ctx, struct gl_vertex_program *prog,
304 GLenum target, GLuint id)
305 {
306 if (prog)
307 return _mesa_init_program_struct( ctx, &prog->Base, target, id );
308 else
309 return NULL;
310 }
311
312
313 /**
314 * Initialize a new geometry program object.
315 */
316 struct gl_program *
317 _mesa_init_geometry_program( struct gl_context *ctx, struct gl_geometry_program *prog,
318 GLenum target, GLuint id)
319 {
320 if (prog)
321 return _mesa_init_program_struct( ctx, &prog->Base, target, id );
322 else
323 return NULL;
324 }
325
326
327 /**
328 * Allocate and initialize a new fragment/vertex program object but
329 * don't put it into the program hash table. Called via
330 * ctx->Driver.NewProgram. May be overridden (ie. replaced) by a
331 * device driver function to implement OO deriviation with additional
332 * types not understood by this function.
333 *
334 * \param ctx context
335 * \param id program id/number
336 * \param target program target/type
337 * \return pointer to new program object
338 */
339 struct gl_program *
340 _mesa_new_program(struct gl_context *ctx, GLenum target, GLuint id)
341 {
342 struct gl_program *prog;
343 switch (target) {
344 case GL_VERTEX_PROGRAM_ARB: /* == GL_VERTEX_PROGRAM_NV */
345 case GL_VERTEX_STATE_PROGRAM_NV:
346 prog = _mesa_init_vertex_program(ctx, CALLOC_STRUCT(gl_vertex_program),
347 target, id );
348 break;
349 case GL_FRAGMENT_PROGRAM_NV:
350 case GL_FRAGMENT_PROGRAM_ARB:
351 prog =_mesa_init_fragment_program(ctx,
352 CALLOC_STRUCT(gl_fragment_program),
353 target, id );
354 break;
355 case MESA_GEOMETRY_PROGRAM:
356 prog = _mesa_init_geometry_program(ctx,
357 CALLOC_STRUCT(gl_geometry_program),
358 target, id);
359 break;
360 default:
361 _mesa_problem(ctx, "bad target in _mesa_new_program");
362 prog = NULL;
363 }
364 return prog;
365 }
366
367
368 /**
369 * Delete a program and remove it from the hash table, ignoring the
370 * reference count.
371 * Called via ctx->Driver.DeleteProgram. May be wrapped (OO deriviation)
372 * by a device driver function.
373 */
374 void
375 _mesa_delete_program(struct gl_context *ctx, struct gl_program *prog)
376 {
377 (void) ctx;
378 ASSERT(prog);
379 ASSERT(prog->RefCount==0);
380
381 if (prog == &_mesa_DummyProgram)
382 return;
383
384 if (prog->String)
385 free(prog->String);
386
387 _mesa_free_instructions(prog->Instructions, prog->NumInstructions);
388
389 if (prog->Parameters) {
390 _mesa_free_parameter_list(prog->Parameters);
391 }
392 if (prog->Varying) {
393 _mesa_free_parameter_list(prog->Varying);
394 }
395 if (prog->Attributes) {
396 _mesa_free_parameter_list(prog->Attributes);
397 }
398
399 free(prog);
400 }
401
402
403 /**
404 * Return the gl_program object for a given ID.
405 * Basically just a wrapper for _mesa_HashLookup() to avoid a lot of
406 * casts elsewhere.
407 */
408 struct gl_program *
409 _mesa_lookup_program(struct gl_context *ctx, GLuint id)
410 {
411 if (id)
412 return (struct gl_program *) _mesa_HashLookup(ctx->Shared->Programs, id);
413 else
414 return NULL;
415 }
416
417
418 /**
419 * Reference counting for vertex/fragment programs
420 */
421 void
422 _mesa_reference_program(struct gl_context *ctx,
423 struct gl_program **ptr,
424 struct gl_program *prog)
425 {
426 assert(ptr);
427 if (*ptr && prog) {
428 /* sanity check */
429 if ((*ptr)->Target == GL_VERTEX_PROGRAM_ARB)
430 ASSERT(prog->Target == GL_VERTEX_PROGRAM_ARB);
431 else if ((*ptr)->Target == GL_FRAGMENT_PROGRAM_ARB)
432 ASSERT(prog->Target == GL_FRAGMENT_PROGRAM_ARB ||
433 prog->Target == GL_FRAGMENT_PROGRAM_NV);
434 else if ((*ptr)->Target == MESA_GEOMETRY_PROGRAM)
435 ASSERT(prog->Target == MESA_GEOMETRY_PROGRAM);
436 }
437 if (*ptr == prog) {
438 return; /* no change */
439 }
440 if (*ptr) {
441 GLboolean deleteFlag;
442
443 /*_glthread_LOCK_MUTEX((*ptr)->Mutex);*/
444 #if 0
445 printf("Program %p ID=%u Target=%s Refcount-- to %d\n",
446 *ptr, (*ptr)->Id,
447 ((*ptr)->Target == GL_VERTEX_PROGRAM_ARB ? "VP" :
448 ((*ptr)->Target == MESA_GEOMETRY_PROGRAM ? "GP" : "FP")),
449 (*ptr)->RefCount - 1);
450 #endif
451 ASSERT((*ptr)->RefCount > 0);
452 (*ptr)->RefCount--;
453
454 deleteFlag = ((*ptr)->RefCount == 0);
455 /*_glthread_UNLOCK_MUTEX((*ptr)->Mutex);*/
456
457 if (deleteFlag) {
458 ASSERT(ctx);
459 ctx->Driver.DeleteProgram(ctx, *ptr);
460 }
461
462 *ptr = NULL;
463 }
464
465 assert(!*ptr);
466 if (prog) {
467 /*_glthread_LOCK_MUTEX(prog->Mutex);*/
468 prog->RefCount++;
469 #if 0
470 printf("Program %p ID=%u Target=%s Refcount++ to %d\n",
471 prog, prog->Id,
472 (prog->Target == GL_VERTEX_PROGRAM_ARB ? "VP" :
473 (prog->Target == MESA_GEOMETRY_PROGRAM ? "GP" : "FP")),
474 prog->RefCount);
475 #endif
476 /*_glthread_UNLOCK_MUTEX(prog->Mutex);*/
477 }
478
479 *ptr = prog;
480 }
481
482
483 /**
484 * Return a copy of a program.
485 * XXX Problem here if the program object is actually OO-derivation
486 * made by a device driver.
487 */
488 struct gl_program *
489 _mesa_clone_program(struct gl_context *ctx, const struct gl_program *prog)
490 {
491 struct gl_program *clone;
492
493 clone = ctx->Driver.NewProgram(ctx, prog->Target, prog->Id);
494 if (!clone)
495 return NULL;
496
497 assert(clone->Target == prog->Target);
498 assert(clone->RefCount == 1);
499
500 clone->String = (GLubyte *) _mesa_strdup((char *) prog->String);
501 clone->Format = prog->Format;
502 clone->Instructions = _mesa_alloc_instructions(prog->NumInstructions);
503 if (!clone->Instructions) {
504 _mesa_reference_program(ctx, &clone, NULL);
505 return NULL;
506 }
507 _mesa_copy_instructions(clone->Instructions, prog->Instructions,
508 prog->NumInstructions);
509 clone->InputsRead = prog->InputsRead;
510 clone->OutputsWritten = prog->OutputsWritten;
511 clone->SamplersUsed = prog->SamplersUsed;
512 clone->ShadowSamplers = prog->ShadowSamplers;
513 memcpy(clone->TexturesUsed, prog->TexturesUsed, sizeof(prog->TexturesUsed));
514
515 if (prog->Parameters)
516 clone->Parameters = _mesa_clone_parameter_list(prog->Parameters);
517 memcpy(clone->LocalParams, prog->LocalParams, sizeof(clone->LocalParams));
518 if (prog->Varying)
519 clone->Varying = _mesa_clone_parameter_list(prog->Varying);
520 if (prog->Attributes)
521 clone->Attributes = _mesa_clone_parameter_list(prog->Attributes);
522 memcpy(clone->LocalParams, prog->LocalParams, sizeof(clone->LocalParams));
523 clone->IndirectRegisterFiles = prog->IndirectRegisterFiles;
524 clone->NumInstructions = prog->NumInstructions;
525 clone->NumTemporaries = prog->NumTemporaries;
526 clone->NumParameters = prog->NumParameters;
527 clone->NumAttributes = prog->NumAttributes;
528 clone->NumAddressRegs = prog->NumAddressRegs;
529 clone->NumNativeInstructions = prog->NumNativeInstructions;
530 clone->NumNativeTemporaries = prog->NumNativeTemporaries;
531 clone->NumNativeParameters = prog->NumNativeParameters;
532 clone->NumNativeAttributes = prog->NumNativeAttributes;
533 clone->NumNativeAddressRegs = prog->NumNativeAddressRegs;
534 clone->NumAluInstructions = prog->NumAluInstructions;
535 clone->NumTexInstructions = prog->NumTexInstructions;
536 clone->NumTexIndirections = prog->NumTexIndirections;
537 clone->NumNativeAluInstructions = prog->NumNativeAluInstructions;
538 clone->NumNativeTexInstructions = prog->NumNativeTexInstructions;
539 clone->NumNativeTexIndirections = prog->NumNativeTexIndirections;
540
541 switch (prog->Target) {
542 case GL_VERTEX_PROGRAM_ARB:
543 {
544 const struct gl_vertex_program *vp
545 = (const struct gl_vertex_program *) prog;
546 struct gl_vertex_program *vpc = (struct gl_vertex_program *) clone;
547 vpc->IsPositionInvariant = vp->IsPositionInvariant;
548 vpc->IsNVProgram = vp->IsNVProgram;
549 }
550 break;
551 case GL_FRAGMENT_PROGRAM_ARB:
552 {
553 const struct gl_fragment_program *fp
554 = (const struct gl_fragment_program *) prog;
555 struct gl_fragment_program *fpc = (struct gl_fragment_program *) clone;
556 fpc->FogOption = fp->FogOption;
557 fpc->UsesKill = fp->UsesKill;
558 fpc->OriginUpperLeft = fp->OriginUpperLeft;
559 fpc->PixelCenterInteger = fp->PixelCenterInteger;
560 }
561 break;
562 case MESA_GEOMETRY_PROGRAM:
563 {
564 const struct gl_geometry_program *gp
565 = (const struct gl_geometry_program *) prog;
566 struct gl_geometry_program *gpc = (struct gl_geometry_program *) clone;
567 gpc->VerticesOut = gp->VerticesOut;
568 gpc->InputType = gp->InputType;
569 gpc->OutputType = gp->OutputType;
570 }
571 break;
572 default:
573 _mesa_problem(NULL, "Unexpected target in _mesa_clone_program");
574 }
575
576 return clone;
577 }
578
579
580 /**
581 * Insert 'count' NOP instructions at 'start' in the given program.
582 * Adjust branch targets accordingly.
583 */
584 GLboolean
585 _mesa_insert_instructions(struct gl_program *prog, GLuint start, GLuint count)
586 {
587 const GLuint origLen = prog->NumInstructions;
588 const GLuint newLen = origLen + count;
589 struct prog_instruction *newInst;
590 GLuint i;
591
592 /* adjust branches */
593 for (i = 0; i < prog->NumInstructions; i++) {
594 struct prog_instruction *inst = prog->Instructions + i;
595 if (inst->BranchTarget > 0) {
596 if ((GLuint)inst->BranchTarget >= start) {
597 inst->BranchTarget += count;
598 }
599 }
600 }
601
602 /* Alloc storage for new instructions */
603 newInst = _mesa_alloc_instructions(newLen);
604 if (!newInst) {
605 return GL_FALSE;
606 }
607
608 /* Copy 'start' instructions into new instruction buffer */
609 _mesa_copy_instructions(newInst, prog->Instructions, start);
610
611 /* init the new instructions */
612 _mesa_init_instructions(newInst + start, count);
613
614 /* Copy the remaining/tail instructions to new inst buffer */
615 _mesa_copy_instructions(newInst + start + count,
616 prog->Instructions + start,
617 origLen - start);
618
619 /* free old instructions */
620 _mesa_free_instructions(prog->Instructions, origLen);
621
622 /* install new instructions */
623 prog->Instructions = newInst;
624 prog->NumInstructions = newLen;
625
626 return GL_TRUE;
627 }
628
629 /**
630 * Delete 'count' instructions at 'start' in the given program.
631 * Adjust branch targets accordingly.
632 */
633 GLboolean
634 _mesa_delete_instructions(struct gl_program *prog, GLuint start, GLuint count)
635 {
636 const GLuint origLen = prog->NumInstructions;
637 const GLuint newLen = origLen - count;
638 struct prog_instruction *newInst;
639 GLuint i;
640
641 /* adjust branches */
642 for (i = 0; i < prog->NumInstructions; i++) {
643 struct prog_instruction *inst = prog->Instructions + i;
644 if (inst->BranchTarget > 0) {
645 if (inst->BranchTarget > (GLint) start) {
646 inst->BranchTarget -= count;
647 }
648 }
649 }
650
651 /* Alloc storage for new instructions */
652 newInst = _mesa_alloc_instructions(newLen);
653 if (!newInst) {
654 return GL_FALSE;
655 }
656
657 /* Copy 'start' instructions into new instruction buffer */
658 _mesa_copy_instructions(newInst, prog->Instructions, start);
659
660 /* Copy the remaining/tail instructions to new inst buffer */
661 _mesa_copy_instructions(newInst + start,
662 prog->Instructions + start + count,
663 newLen - start);
664
665 /* free old instructions */
666 _mesa_free_instructions(prog->Instructions, origLen);
667
668 /* install new instructions */
669 prog->Instructions = newInst;
670 prog->NumInstructions = newLen;
671
672 return GL_TRUE;
673 }
674
675
676 /**
677 * Search instructions for registers that match (oldFile, oldIndex),
678 * replacing them with (newFile, newIndex).
679 */
680 static void
681 replace_registers(struct prog_instruction *inst, GLuint numInst,
682 GLuint oldFile, GLuint oldIndex,
683 GLuint newFile, GLuint newIndex)
684 {
685 GLuint i, j;
686 for (i = 0; i < numInst; i++) {
687 /* src regs */
688 for (j = 0; j < _mesa_num_inst_src_regs(inst[i].Opcode); j++) {
689 if (inst[i].SrcReg[j].File == oldFile &&
690 inst[i].SrcReg[j].Index == oldIndex) {
691 inst[i].SrcReg[j].File = newFile;
692 inst[i].SrcReg[j].Index = newIndex;
693 }
694 }
695 /* dst reg */
696 if (inst[i].DstReg.File == oldFile && inst[i].DstReg.Index == oldIndex) {
697 inst[i].DstReg.File = newFile;
698 inst[i].DstReg.Index = newIndex;
699 }
700 }
701 }
702
703
704 /**
705 * Search instructions for references to program parameters. When found,
706 * increment the parameter index by 'offset'.
707 * Used when combining programs.
708 */
709 static void
710 adjust_param_indexes(struct prog_instruction *inst, GLuint numInst,
711 GLuint offset)
712 {
713 GLuint i, j;
714 for (i = 0; i < numInst; i++) {
715 for (j = 0; j < _mesa_num_inst_src_regs(inst[i].Opcode); j++) {
716 GLuint f = inst[i].SrcReg[j].File;
717 if (f == PROGRAM_CONSTANT ||
718 f == PROGRAM_UNIFORM ||
719 f == PROGRAM_STATE_VAR) {
720 inst[i].SrcReg[j].Index += offset;
721 }
722 }
723 }
724 }
725
726
727 /**
728 * Combine two programs into one. Fix instructions so the outputs of
729 * the first program go to the inputs of the second program.
730 */
731 struct gl_program *
732 _mesa_combine_programs(struct gl_context *ctx,
733 const struct gl_program *progA,
734 const struct gl_program *progB)
735 {
736 struct prog_instruction *newInst;
737 struct gl_program *newProg;
738 const GLuint lenA = progA->NumInstructions - 1; /* omit END instr */
739 const GLuint lenB = progB->NumInstructions;
740 const GLuint numParamsA = _mesa_num_parameters(progA->Parameters);
741 const GLuint newLength = lenA + lenB;
742 GLboolean usedTemps[MAX_PROGRAM_TEMPS];
743 GLuint firstTemp = 0;
744 GLbitfield inputsB;
745 GLuint i;
746
747 ASSERT(progA->Target == progB->Target);
748
749 newInst = _mesa_alloc_instructions(newLength);
750 if (!newInst)
751 return GL_FALSE;
752
753 _mesa_copy_instructions(newInst, progA->Instructions, lenA);
754 _mesa_copy_instructions(newInst + lenA, progB->Instructions, lenB);
755
756 /* adjust branch / instruction addresses for B's instructions */
757 for (i = 0; i < lenB; i++) {
758 newInst[lenA + i].BranchTarget += lenA;
759 }
760
761 newProg = ctx->Driver.NewProgram(ctx, progA->Target, 0);
762 newProg->Instructions = newInst;
763 newProg->NumInstructions = newLength;
764
765 /* find used temp regs (we may need new temps below) */
766 _mesa_find_used_registers(newProg, PROGRAM_TEMPORARY,
767 usedTemps, MAX_PROGRAM_TEMPS);
768
769 if (newProg->Target == GL_FRAGMENT_PROGRAM_ARB) {
770 struct gl_fragment_program *fprogA, *fprogB, *newFprog;
771 GLbitfield progB_inputsRead = progB->InputsRead;
772 GLint progB_colorFile, progB_colorIndex;
773
774 fprogA = (struct gl_fragment_program *) progA;
775 fprogB = (struct gl_fragment_program *) progB;
776 newFprog = (struct gl_fragment_program *) newProg;
777
778 newFprog->UsesKill = fprogA->UsesKill || fprogB->UsesKill;
779
780 /* We'll do a search and replace for instances
781 * of progB_colorFile/progB_colorIndex below...
782 */
783 progB_colorFile = PROGRAM_INPUT;
784 progB_colorIndex = FRAG_ATTRIB_COL0;
785
786 /*
787 * The fragment program may get color from a state var rather than
788 * a fragment input (vertex output) if it's constant.
789 * See the texenvprogram.c code.
790 * So, search the program's parameter list now to see if the program
791 * gets color from a state var instead of a conventional fragment
792 * input register.
793 */
794 for (i = 0; i < progB->Parameters->NumParameters; i++) {
795 struct gl_program_parameter *p = &progB->Parameters->Parameters[i];
796 if (p->Type == PROGRAM_STATE_VAR &&
797 p->StateIndexes[0] == STATE_INTERNAL &&
798 p->StateIndexes[1] == STATE_CURRENT_ATTRIB &&
799 p->StateIndexes[2] == VERT_ATTRIB_COLOR0) {
800 progB_inputsRead |= FRAG_BIT_COL0;
801 progB_colorFile = PROGRAM_STATE_VAR;
802 progB_colorIndex = i;
803 break;
804 }
805 }
806
807 /* Connect color outputs of fprogA to color inputs of fprogB, via a
808 * new temporary register.
809 */
810 if ((progA->OutputsWritten & (1 << FRAG_RESULT_COLOR)) &&
811 (progB_inputsRead & FRAG_BIT_COL0)) {
812 GLint tempReg = _mesa_find_free_register(usedTemps, MAX_PROGRAM_TEMPS,
813 firstTemp);
814 if (tempReg < 0) {
815 _mesa_problem(ctx, "No free temp regs found in "
816 "_mesa_combine_programs(), using 31");
817 tempReg = 31;
818 }
819 firstTemp = tempReg + 1;
820
821 /* replace writes to result.color[0] with tempReg */
822 replace_registers(newInst, lenA,
823 PROGRAM_OUTPUT, FRAG_RESULT_COLOR,
824 PROGRAM_TEMPORARY, tempReg);
825 /* replace reads from the input color with tempReg */
826 replace_registers(newInst + lenA, lenB,
827 progB_colorFile, progB_colorIndex, /* search for */
828 PROGRAM_TEMPORARY, tempReg /* replace with */ );
829 }
830
831 /* compute combined program's InputsRead */
832 inputsB = progB_inputsRead;
833 if (progA->OutputsWritten & (1 << FRAG_RESULT_COLOR)) {
834 inputsB &= ~(1 << FRAG_ATTRIB_COL0);
835 }
836 newProg->InputsRead = progA->InputsRead | inputsB;
837 newProg->OutputsWritten = progB->OutputsWritten;
838 newProg->SamplersUsed = progA->SamplersUsed | progB->SamplersUsed;
839 }
840 else {
841 /* vertex program */
842 assert(0); /* XXX todo */
843 }
844
845 /*
846 * Merge parameters (uniforms, constants, etc)
847 */
848 newProg->Parameters = _mesa_combine_parameter_lists(progA->Parameters,
849 progB->Parameters);
850
851 adjust_param_indexes(newInst + lenA, lenB, numParamsA);
852
853
854 return newProg;
855 }
856
857
858 /**
859 * Populate the 'used' array with flags indicating which registers (TEMPs,
860 * INPUTs, OUTPUTs, etc, are used by the given program.
861 * \param file type of register to scan for
862 * \param used returns true/false flags for in use / free
863 * \param usedSize size of the 'used' array
864 */
865 void
866 _mesa_find_used_registers(const struct gl_program *prog,
867 gl_register_file file,
868 GLboolean used[], GLuint usedSize)
869 {
870 GLuint i, j;
871
872 memset(used, 0, usedSize);
873
874 for (i = 0; i < prog->NumInstructions; i++) {
875 const struct prog_instruction *inst = prog->Instructions + i;
876 const GLuint n = _mesa_num_inst_src_regs(inst->Opcode);
877
878 if (inst->DstReg.File == file) {
879 ASSERT(inst->DstReg.Index < usedSize);
880 if(inst->DstReg.Index < usedSize)
881 used[inst->DstReg.Index] = GL_TRUE;
882 }
883
884 for (j = 0; j < n; j++) {
885 if (inst->SrcReg[j].File == file) {
886 ASSERT(inst->SrcReg[j].Index < usedSize);
887 if(inst->SrcReg[j].Index < usedSize)
888 used[inst->SrcReg[j].Index] = GL_TRUE;
889 }
890 }
891 }
892 }
893
894
895 /**
896 * Scan the given 'used' register flag array for the first entry
897 * that's >= firstReg.
898 * \param used vector of flags indicating registers in use (as returned
899 * by _mesa_find_used_registers())
900 * \param usedSize size of the 'used' array
901 * \param firstReg first register to start searching at
902 * \return index of unused register, or -1 if none.
903 */
904 GLint
905 _mesa_find_free_register(const GLboolean used[],
906 GLuint usedSize, GLuint firstReg)
907 {
908 GLuint i;
909
910 assert(firstReg < usedSize);
911
912 for (i = firstReg; i < usedSize; i++)
913 if (!used[i])
914 return i;
915
916 return -1;
917 }
918
919
920 /**
921 * "Post-process" a GPU program. This is intended to be used for debugging.
922 * Example actions include no-op'ing instructions or changing instruction
923 * behaviour.
924 */
925 void
926 _mesa_postprocess_program(struct gl_context *ctx, struct gl_program *prog)
927 {
928 static const GLfloat white[4] = { 0.5, 0.5, 0.5, 0.5 };
929 GLuint i;
930 GLuint whiteSwizzle;
931 GLint whiteIndex = _mesa_add_unnamed_constant(prog->Parameters,
932 white, 4, &whiteSwizzle);
933
934 (void) whiteIndex;
935
936 for (i = 0; i < prog->NumInstructions; i++) {
937 struct prog_instruction *inst = prog->Instructions + i;
938 const GLuint n = _mesa_num_inst_src_regs(inst->Opcode);
939
940 (void) n;
941
942 if (_mesa_is_tex_instruction(inst->Opcode)) {
943 #if 0
944 /* replace TEX/TXP/TXB with MOV */
945 inst->Opcode = OPCODE_MOV;
946 inst->DstReg.WriteMask = WRITEMASK_XYZW;
947 inst->SrcReg[0].Swizzle = SWIZZLE_XYZW;
948 inst->SrcReg[0].Negate = NEGATE_NONE;
949 #endif
950
951 #if 0
952 /* disable shadow texture mode */
953 inst->TexShadow = 0;
954 #endif
955 }
956
957 if (inst->Opcode == OPCODE_TXP) {
958 #if 0
959 inst->Opcode = OPCODE_MOV;
960 inst->DstReg.WriteMask = WRITEMASK_XYZW;
961 inst->SrcReg[0].File = PROGRAM_CONSTANT;
962 inst->SrcReg[0].Index = whiteIndex;
963 inst->SrcReg[0].Swizzle = SWIZZLE_XYZW;
964 inst->SrcReg[0].Negate = NEGATE_NONE;
965 #endif
966 #if 0
967 inst->TexShadow = 0;
968 #endif
969 #if 0
970 inst->Opcode = OPCODE_TEX;
971 inst->TexShadow = 0;
972 #endif
973 }
974
975 }
976 }