The current GLSL linker puts varyings in slots starting from *_VAR0,
leaving the *_TEX slots used only for gl_TexCoord[i].

This results in TGSI programs that start using generic input/outputs
with index 10.

Unfortunately, some drivers (e.g. pre-nv50 nouveau) support only 8
vertex program outputs, and this causes GLSL to not work at all.
On other cards, GLSL works, but 8 varying slots are lost.

This patch solves the problem by modifying the GLSL linker to allocate
varyings in texcoord slots that neither vertex nor fragment shader uses.

Note that the GLSL linker is the only place where this can be done,
because it is the only place that sees both the vertex and fragment
programs at once.

The only known issue is that if the GLSL program has an indirect
reference to gl_TexCoord[i], no varyings will be put in texcoord slots.
This may or may not be desirable.

This makes (a subset of) GLSL work on NV30/NV40 and improves the
chances of complex programs working on other cards.

Signed-off-by: Luca Barbieri <l...@luca-barbieri.com>
---
 src/mesa/shader/slang/slang_link.c |   62 ++++++++++++++++++++++++++---------
 1 files changed, 46 insertions(+), 16 deletions(-)

diff --git a/src/mesa/shader/slang/slang_link.c 
b/src/mesa/shader/slang/slang_link.c
index ed27821..889a811 100644
--- a/src/mesa/shader/slang/slang_link.c
+++ b/src/mesa/shader/slang/slang_link.c
@@ -99,9 +99,9 @@ bits_agree(GLbitfield flags1, GLbitfield flags2, GLbitfield 
bit)
  */
 static GLboolean
 link_varying_vars(GLcontext *ctx,
-                  struct gl_shader_program *shProg, struct gl_program *prog)
+                  struct gl_shader_program *shProg, struct gl_program *prog, 
GLbyte* varying_slots)
 {
-   GLuint *map, i, firstVarying, newFile;
+   GLuint *map, i, firstTex, firstVarying, newFile;
    GLbitfield *inOutFlags;
 
    map = (GLuint *) _mesa_malloc(prog->Varying->NumParameters * 
sizeof(GLuint));
@@ -114,13 +114,15 @@ link_varying_vars(GLcontext *ctx,
     * Also, replace File=PROGRAM_VARYING with File=PROGRAM_INPUT/OUTPUT.
     */
    if (prog->Target == GL_VERTEX_PROGRAM_ARB) {
-      firstVarying = VERT_RESULT_VAR0;
+      firstTex = VERT_RESULT_TEX0;
+      firstVarying = VERT_RESULT_VAR0 - 8;
       newFile = PROGRAM_OUTPUT;
       inOutFlags = prog->OutputFlags;
    }
    else {
       assert(prog->Target == GL_FRAGMENT_PROGRAM_ARB);
-      firstVarying = FRAG_ATTRIB_VAR0;
+      firstTex = FRAG_ATTRIB_TEX0;
+      firstVarying = FRAG_ATTRIB_VAR0 - 8;
       newFile = PROGRAM_INPUT;
       inOutFlags = prog->InputFlags;
    }
@@ -173,9 +175,12 @@ link_varying_vars(GLcontext *ctx,
       {
          GLint sz = var->Size;
          while (sz > 0) {
-            inOutFlags[firstVarying + j] = var->Flags;
+            int v = varying_slots[j];
+            v += ((v < 8) ? firstTex : firstVarying);
+            inOutFlags[v] = var->Flags;
             /*printf("Link varying from %d to %d\n", i, j);*/
-            map[i++] = j++;
+            map[i++] = v;
+            ++j;
             sz -= 4;
          }
          i--; /* go back one */
@@ -192,13 +197,13 @@ link_varying_vars(GLcontext *ctx,
 
       if (inst->DstReg.File == PROGRAM_VARYING) {
          inst->DstReg.File = newFile;
-         inst->DstReg.Index = map[ inst->DstReg.Index ] + firstVarying;
+         inst->DstReg.Index = map[ inst->DstReg.Index ];
       }
 
       for (j = 0; j < 3; j++) {
          if (inst->SrcReg[j].File == PROGRAM_VARYING) {
             inst->SrcReg[j].File = newFile;
-            inst->SrcReg[j].Index = map[ inst->SrcReg[j].Index ] + 
firstVarying;
+            inst->SrcReg[j].Index = map[ inst->SrcReg[j].Index ];
          }
       }
    }
@@ -790,14 +795,39 @@ _slang_link(GLcontext *ctx,
       ASSERT(shProg->FragmentProgram->Base.RefCount == 1);
    }
 
-   /* link varying vars */
-   if (shProg->VertexProgram) {
-      if (!link_varying_vars(ctx, shProg, &shProg->VertexProgram->Base))
-         return;
-   }
-   if (shProg->FragmentProgram) {
-      if (!link_varying_vars(ctx, shProg, &shProg->FragmentProgram->Base))
-         return;
+   {
+      GLuint texcoord_mask = 0;
+      GLbyte varying_slots[MAX_VARYING];
+      GLuint next_varying = 0;
+
+      if(shProg->VertexProgram)
+      {
+            _slang_update_inputs_outputs(&shProg->VertexProgram->Base);
+            texcoord_mask |= (shProg->VertexProgram->Base.OutputsWritten >> 
VERT_RESULT_TEX0) & 0xff;
+      }
+      if(shProg->FragmentProgram)
+      {
+            _slang_update_inputs_outputs(&shProg->FragmentProgram->Base);
+            texcoord_mask |= (shProg->FragmentProgram->Base.InputsRead >> 
FRAG_ATTRIB_TEX0) & 0xff;
+      }
+
+      /* Allocate varying slots, excluding slot i if gl_TexCoord[i] is used by 
the shaders */
+      for(i = 0; i < MAX_VARYING; ++i)
+      {
+         for(; (1 << next_varying) & texcoord_mask; ++next_varying)
+         {}
+         varying_slots[i] = next_varying++;
+      }
+
+      /* link varying vars */
+      if (shProg->VertexProgram) {
+         if (!link_varying_vars(ctx, shProg, &shProg->VertexProgram->Base, 
varying_slots))
+            return;
+      }
+      if (shProg->FragmentProgram) {
+         if (!link_varying_vars(ctx, shProg, &shProg->FragmentProgram->Base, 
varying_slots))
+            return;
+      }
    }
 
    /* link uniform vars */
-- 
1.6.3.3


------------------------------------------------------------------------------
Throughout its 18-year history, RSA Conference consistently attracts the
world's best and brightest in the field, creating opportunities for Conference
attendees to learn about information security's most important issues through
interactions with peers, luminaries and emerging and established companies.
http://p.sf.net/sfu/rsaconf-dev2dev
_______________________________________________
Mesa3d-dev mailing list
Mesa3d-dev@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mesa3d-dev

Reply via email to