1 Reply Latest reply on Jan 12, 2011 2:33 AM by frali

    Unspecified link error on ATI X1250 in shader sampling texture multiple times



      I'm developing on a laptop with an integrated Radeon X1250 GPU. I'm writing a fragment shader to do bilinear interpolation manually (it's a long story, but absolutely necessary). This involves a fair amount of slow computations and four texture samples per fragment. The shader compiles, the log contains no errors, but the linker fails with this message:


      Fragment shader(s) failed to link,  vertex shader(s) linked.

      Below is the complete shader. If I remove a single fetch, it links. Likewise, if I use constant texel coordinates for one of the fetches, like so:

      c[0] = FetchTexel(vec2(0.0,0.0),fsSubTexture.xy,fsSubTexture.zw,fsTexParams.zw);

      It works as well. I've also tried manually inlining the FetchTexel() function to no avail. The program works fine on a desktop Nvidia machine. I'd like this code to run on lower spec hardware so I'm really hoping I'm not bumping into any sort of weird limitations here.

      Thank you!


       * fragment.glsl
       * Fragment shader.

      #version 120

      // Global uniforms
      uniform sampler2D textureMap;  // complete texture map, 2048x2048 texels
      uniform vec3  polygonState; // .x=not defined, .y=not defined, .z=alpha processing enable

      // Inputs from vertex shader
      varying vec4  fsSubTexture; // .x=texture X, .y=texture Y, .z=texture width, .w=texture height (all in texels)
      varying vec4  fsTexParams; // .x=texture enable (if 1, else 0), .y=use transparency (if >=0), .z=U wrap mode (1=mirror, 0=repeat), .w=V wrap mode
      varying float  fsTransLevel; // translucence level, 0.0 (transparent) to 1.0 (opaque). if less than 1.0, replace alpha value
      varying float  fsLightIntensity; // lighting intensity

       * FetchTexel():
       * Samples a single Real3D texel from the selected texture, taking into
       * account wrapping behavior.
       * Computing normalized OpenGL texture coordinates (0 to 1) within the
       * Real3D texture sheet:
       * If the texture is not mirrored, we simply have to clamp the
       * coordinates to fit within the texture dimensions, add the texture
       * X, Y position to select the appropriate one, and normalize by 2048
       * (the dimensions of the Real3D texture sheet).
       *  = [(u,v)%(w,h)+(x,y)]/(2048,2048)
       * If mirroring is enabled, textures are mirrored every odd multiple of
       * the original texture. To detect whether we are in an odd multiple,
       * simply divide the coordinate by the texture dimension and check
       * whether the result is odd. Then, clamp the coordinates as before but
       * subtract from the dimension to mirror them:
       *   = [M*((w,h)-(u,v)%(w,h)) + (1-M)*(u,v)%(w,h) + (x,y)]/(2048,2048)
       *  where M is 1.0 if the texture must be mirrored.
      vec4 FetchTexel(vec2 texCoord, vec2 texOffset, vec2 texSize, vec2 mirrorEnable)
       vec2 clampedCoord, mirror, glTexCoord;
       clampedCoord = mod(texCoord.st,texSize);      // clamp coordinates to within texture size
       mirror = mirrorEnable * mod(floor(texCoord.st/texSize),2.0); // whether this texel needs to be mirrored
       glTexCoord = ( mirror*(texSize-clampedCoord) +
           (vec2(1.0,1.0)-mirror)*clampedCoord +
           ) / 2048.0;
       return texture2D(textureMap, glTexCoord);

      void main(void)

       vec4 c[4];
       vec2 uv[4], r;
       if (fsTexParams.x == 0.0)
        gl_FragColor = gl_Color; // if textures disabled, use color
         * Bilinear Filtering
        // Compute fractional blending factor, r, and lower left corner of texel 0
        uv[0] = gl_TexCoord[0].st-vec2(0.5,0.5);
        r = uv[0]-floor(uv[0]);
        uv[0] = floor(uv[0]);
        // Compute texel coordinates
        uv[0] = uv[0] + vec2(0.5,0.5); // offset to within center of pixel
        uv[1] = uv[0] + vec2(1.0,0.0);
        uv[2] = uv[0] + vec2(0.0,1.0);
        uv[3] = uv[0] + vec2(1.0,1.0);
        // Fetch texels
        c[0] = FetchTexel(uv[0],fsSubTexture.xy,fsSubTexture.zw,fsTexParams.zw);
        c[1] = FetchTexel(uv[1],fsSubTexture.xy,fsSubTexture.zw,fsTexParams.zw);
        c[2] = FetchTexel(uv[2],fsSubTexture.xy,fsSubTexture.zw,fsTexParams.zw);
        c[3] = FetchTexel(uv[3],fsSubTexture.xy,fsSubTexture.zw,fsTexParams.zw);

        gl_FragColor = c[0]*(1-r.s)*(1-r.t) + c[1]*r.s*(1-r.t) + c[2]*(1-r.s)*r.t + c[3]*r.s*r.t;
         * T1RGB5:
         * The transparency bit determines whether to discard pixels (if set).
         * What is unknown is how this bit behaves when interpolated. OpenGL
         * processes it as an alpha value, so it might concievably be blended
         * with neighbors. Here, an arbitrary threshold is chosen.
        if (fsTexParams.y >= 0.0)
         if (gl_FragColor.a > 0.0)
       // Apply translucency
       if (fsTransLevel < 1.0)
         gl_FragColor.a = fsTransLevel;
       // Apply ambient lighting
       gl_FragColor.rgb *= fsLightIntensity;