Two questions about textures in fragment program

Hello. I’m using the following fragment program:

uniform sampler2D top : TEXUNIT1;
uniform sampler2D mid : TEXUNIT2;
uniform sampler2D low : TEXUNIT3;

uniform float3    LightPos;            

struct vertexOut {
	float2 UV        : TEXCOORD0;
	float3 WorldPos  : TEXCOORD1;
	float3 normal    : TEXCOORD2;
	float3 TexW      : TEXCOORD3;

float4 main(vertexOut In) : COLOR {

	float3 normal = normalize(;
	float3 l      = normalize(LightPos-In.WorldPos);
	float coff    = max(dot(normal, l), 0.0);

	float2 dx = ddx(In.UV);
	float2 dy = ddy(In.UV);

	float3 lowcol = f3tex2D(low, In.UV, dx, dy)*In.TexW.x;
	float3 midcol = f3tex2D(mid, In.UV, dx, dy)*In.TexW.y;
	float3 topcol = f3tex2D(top, In.UV, dx, dy)*In.TexW.z;

	float3 col = (lowcol+midcol+topcol) * coff;

	return float4(col, 1.0);

I have two problems:

First of all, from what I can tell it’s always using the same MipMap level: I have even tried tex2Dlod(low, float4(In.UV, 0, 8), same for mid/high, there was no difference. I’m building my textures using gluBuild2DMipmaps() and setting min. filter to Mipmap linear.

I’m guessing I missed something obvious, so any suggestions are very welcome!

Using hardcoded colors for the low-,mid- and top-col yields a framerate at about 700FPS. Looking only lowcol up in texture decreases framerate by 50%… which seems a lot to me (gets even worse when looking up mid- and topcol). All three textures are 512x512. Is it normal for texture lookups to be this expensive performance-wise?


uniform sampler2D EarthNight;
varying vec2 TexCoord;

nighttime = texture2D(EarthNight, TexCoord,MIP).rgb;

Tweaking th MIP value from 0 to 4 does work on my setup. Check that you don’ hit a but in glubuildmipmaps (it is outdated anyways, instead use hardware automatic mipmap generation).

  1. yes, texture sampling is slow. When comparing benchmark performance, use milliseconds, not FPS, as frames divised by time is not linear.

From the code layout, I’m assuming you’re using Cg as the shading language? If so, try this…

//on context creation
cgGLSetManageTextureParameters(context_goes_here, CG_TRUE);

//before drawing call
cgGLSetupSampler(cgGetNamedEffectParameter(effect_goes here,“low”),low_tex_id_goes_here);

Make sure to call this before setting cgSetPassState(…)

In your shader, use:

uniform sampler2D low = sampler_state {
minFilter = LinearMipmapLinear;
magFilter = Linear;

If you can’t use tex2Dlod now, there’s something wrong with your texture setup.

  1. Yes, this is normal. Recent GPUs spend most of their transistors on ALUs and not on texture fetching components, meaning that they are optimized for arithmetic instructions and not for texture fetching. On older GPUs this wasn’t the case. Back then, fetching values from a cube map for 3D vector normalization was faster than performing the necessary math operations, this isn’t the case anymore. In short, ALU ops are faster than texture fetches.


Thanks for the replies… I managed to solve both problems:

First I tried packing my three textures t1, t2 and t3 (all with unsigned bytes) into one texture t using:

t.r = t1.r256 + t2.r + t3.r/256
t.g = t1.g
256 + t2.g + t3.g/256
t.b = t1.b*256 + t2.b + t3.b/256

with t internal format GL_RGBA_FLOAT32_ATI. This meant only one texture lookup instead of three but quite a lot more math (which, as was stated above, was faster than the additional 2 texture lookups) This gave about 75% speed increase.

Right after getting this to work I stumbled across the texture format GL_COMPRESSED_RGBA_S3TC_DXT3_EXT… after using this I got around 250% speed increase… Would have saved me quite a lot of time if I’d known about that one right away - you live and learn I guess.

I don’t know why it wasn’t working before:
Previously I did


for my three textures once, right after setting them up.
I moved this and now do it every frame and it seems to work (Note that the specific GL_TEXTURE IDs is only used by these specific 3 textures, so I was assuming the parameters would be intact).

I believe the texParameter calls apply to the texture bound to the given texture target, not the texture unit. So first you have to bind the texture you want to set the filters for.