mesa: Fix bugs in ff fragment shader fog handling
authorIan Romanick <ian.d.romanick@intel.com>
Sat, 16 Apr 2011 01:38:54 +0000 (18:38 -0700)
committerIan Romanick <ian.d.romanick@intel.com>
Fri, 22 Apr 2011 00:33:18 +0000 (17:33 -0700)
This patch fixes two bugs related to fog in the fixed-function
fragment shader generation code.

Fog was only lowered to instructions if MRTs were used.  The fragment
shader assembler always lowers "fog option" code to instructions, and
many drivers (e.g., r300) expect this.

When fog lowering did happen, it was after the instruction count was
checked against implementation limits.  Since fog lowering may add up
to 5 instructions, a program that was below the limits before lowering
may exceed the limits after lowering.

NOTE: This is a candidate for the stable branches.

Reviewed-by: Eric Anholt <eric@anholt.net>
Acked-by: Corbin Simpson <MostAwesomeDude@gmail.com>
Acked-by: Alex Deucher <alexdeucher@gmail.com>
src/mesa/main/ff_fragment_shader.cpp

index 43930a4..b799b29 100644 (file)
@@ -1530,14 +1530,32 @@ create_new_program(struct gl_context *ctx, struct state_key *key,
     */
    emit_arith( &p, OPCODE_END, undef, WRITEMASK_XYZW, 0, undef, undef, undef);
 
+   /* Allocate final instruction array.  This has to be done before calling
+    * _mesa_append_fog_code because that function frees the Base.Instructions.
+    * At this point, Base.Instructions points to stack data, so it's a really
+    * bad idea to free it.
+    */
+   p.program->Base.Instructions
+      = _mesa_alloc_instructions(p.program->Base.NumInstructions);
+   if (!p.program->Base.Instructions) {
+      _mesa_error(ctx, GL_OUT_OF_MEMORY,
+                  "generating tex env program");
+      return;
+   }
+   _mesa_copy_instructions(p.program->Base.Instructions, instBuffer,
+                           p.program->Base.NumInstructions);
+
+   /* Append fog code.  This must be done before checking the program against
+    * the limits becuase it will potentially add some instructions.
+    */
    if (key->fog_enabled) {
       /* Pull fog mode from struct gl_context, the value in the state key is
        * a reduced value and not what is expected in FogOption
        */
       p.program->FogOption = ctx->Fog.Mode;
       p.program->Base.InputsRead |= FRAG_BIT_FOGC;
-   }
-   else {
+
+      _mesa_append_fog_code(ctx, p.program, GL_FALSE);
       p.program->FogOption = GL_NONE;
    }
 
@@ -1552,23 +1570,6 @@ create_new_program(struct gl_context *ctx, struct state_key *key,
 
    ASSERT(p.program->Base.NumInstructions <= MAX_INSTRUCTIONS);
 
-   /* Allocate final instruction array */
-   p.program->Base.Instructions
-      = _mesa_alloc_instructions(p.program->Base.NumInstructions);
-   if (!p.program->Base.Instructions) {
-      _mesa_error(ctx, GL_OUT_OF_MEMORY,
-                  "generating tex env program");
-      return;
-   }
-   _mesa_copy_instructions(p.program->Base.Instructions, instBuffer,
-                           p.program->Base.NumInstructions);
-
-   if (key->num_draw_buffers && p.program->FogOption) {
-      _mesa_append_fog_code(ctx, p.program, GL_FALSE);
-      p.program->FogOption = GL_NONE;
-   }
-
-
    /* Notify driver the fragment program has (actually) changed.
     */
    if (ctx->Driver.ProgramStringNotify) {