Reputation: 1009
I have a shader that performs lighting passes in a deferred renderer. It takes uniforms for various optional features, one of them being shadows.
I want to use the same shader for performing lighting with shadows as without (See my other question here). This works great.
However, there is a problem when I render a light without shadows, and as such don't bind any texture to the shadow sampler, leaving some other texture bound. On my System, running the NVIDIA 346.59 drivers, this produces the following GL error/warning:
Program undefined behavior warning: Sampler object 0 is bound to non-depth texture 0, yet it is used with a program that uses a shadow sampler . This is undefined behavior.
Even though I know that the sampler will not be used if this is the case.
Is there any way to get around this? It seems unnecessary to have to bind some unused placeholder texture just to suppress this warning.
EDIT: Note that this does work. The only issue is the warning being spit out by the driver.
EDIT: Ok, here's my shader. The part relevant to this question is the main() function.
#version 330
#extension GL_ARB_shading_language_420pack : enable
#include "headers/blocks/camera"
#include "headers/blocks/spotlight"
#include "headers/uniform_disks"
#include "headers/shadow/sample_spot"
in vec2 texcrd;
layout(std140, binding=0) uniform CAMERABLOCK { CameraBlock CB; };
layout(std140, binding=1) uniform SPOTLIGHTBLOCK { SpotLightBlock LB; };
uniform int mode;
uniform int shadQuality;
uniform int shadFilter;
layout(binding=0) uniform sampler2D texDiff;
layout(binding=1) uniform sampler2D texNorm;
layout(binding=2) uniform sampler2D texSurf;
layout(binding=3) uniform sampler2D texSpec;
layout(binding=4) uniform sampler2D texAmbi;
layout(binding=5) uniform sampler2D texDepth;
layout(binding=6) uniform sampler2DShadow texShad;
out vec3 fragColour;
vec3 get_view_pos(in vec2 _tc) {
float dep = texture(texDepth, _tc).r * 2.f - 1.f;
vec4 p_pos = vec4(_tc * 2.f - 1.f, dep, 1.f);
vec4 v_pos = CB.invProj * p_pos;
return v_pos.xyz / v_pos.w;
}
float get_shadow_value(vec3 _wpos, vec3 _wsurf) {
vec3 normPos = _wpos + _wsurf*0.04f;
vec4 sc = LB.matrix * vec4(normPos, 1.f);
vec3 shadcrd = sc.xyz / sc.w * 0.5f + 0.5f;
float bias = get_bias(_wsurf, normalize(normPos - LB.position));
if (shadFilter < 2) return sample_shadow(shadcrd, bias, texShad);
else {
if (shadQuality == 0) return sample_shadow_x4(shadcrd, bias, texShad);
if (shadQuality == 1) return sample_shadow_x8(shadcrd, bias, texShad);
if (shadQuality == 2) return sample_shadow_x16(shadcrd, bias, texShad);
}
}
vec3 get_diffuse_value(vec3 _lightDir, vec3 _normal) {
vec3 txDiff = texture(texDiff, texcrd).rgb;
float dotProd = max(dot(-_lightDir, _normal), 0.f);
return LB.colour * txDiff * dotProd;
}
vec3 get_specular_value(vec3 _lightDir, vec3 _normal, vec3 _position) {
vec3 txSpec = texture(texSpec, texcrd).rgb;
vec3 reflection = reflect(_lightDir, _normal);
vec3 dirFromCam = normalize(-_position);
float factor = pow(max(dot(dirFromCam, reflection), 0.f), 50.f);
return LB.colour * txSpec * factor;
}
void main() {
vec3 v_pos = get_view_pos(texcrd);
vec3 v_norm = normalize(texture(texNorm, texcrd).rgb * 2.f - 1.f);
vec3 lightDir = normalize(v_pos - vec3(CB.view * vec4(LB.position, 1.f)));
if (dot(-lightDir, v_norm) < -0.25f) discard;
vec4 wp = CB.invView * vec4(v_pos, 1.f);
vec3 w_pos = wp.xyz / wp.w;
vec3 v_surf = normalize(texture(texSurf, texcrd).rgb * 2.f - 1.f);
vec3 w_surf = normalize(vec3(CB.trnView * vec4(v_surf, 0.f)));
vec3 spotDir = normalize(vec3(CB.view * vec4(LB.direction, 0.f)));
float spotDist = distance(LB.position, w_pos);
float angle = acos(dot(lightDir, spotDir));
if (angle > LB.angle || spotDist > LB.intensity) discard;
bool doShad = bool(mode & 1);
bool doDiff = bool(mode & 2);
bool doSpec = bool(mode & 4);
float shad = 1.f;
if (doShad) shad = get_shadow_value(w_pos, w_surf);
if (shad == 0.f) discard;
vec3 diff = vec3(0.f, 0.f, 0.f);
if (doDiff) diff = get_diffuse_value(lightDir, v_norm);
vec3 spec = vec3(0.f, 0.f, 0.f);
if (doSpec) spec = get_specular_value(lightDir, v_norm, v_pos);
float fovRolf = pow((LB.angle - angle) / (1.f - LB.angle), sqrt(LB.softness));
float dstRolf = 1.f - spotDist / LB.intensity;
float rolloff = fovRolf * dstRolf;
fragColour = (diff + spec) * shad * rolloff;
}
Upvotes: 1
Views: 2391
Reputation: 910
After running into this problem and did some digging, I found another way that does not require you to use macros. So the idea is to simply address the warning. I created a fake texture of 1x1 and GL_DEPTHCOMPONENT16 type and also have the filtering mode set to:
glTexParameteri(mTextureTarget, GL_TEXTURE_MIN_FILTER, supportsMipMaps && getTextureInfo().mMipCount > 1 ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
glTexParameteri(mTextureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(mTextureTarget, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
glTexParameteri(mTextureTarget, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
If you want to optimize it, what you can do is in your ShaderObject class (or w/e object that represents a GLShader), during your reflection of the uniforms in your shader, see if you have a shadowSampler2D type (I just always hard-coded mine to unit 15 and I looked for that). If you do have that type and during the rendering call (right before you bind your shader), you still don't have unit 15 binded, bind your fake texture along with the filtering methods.
Also you need to call glUseProgram(0) before you clear things else any program with that shader will still issue the warning.
Upvotes: 1
Reputation: 962
I have read your other question too.
What you would normally do is compile a shader with all required/used samplers, and not expose any unused samplers. Doing so is likely to give you errors.
I know you don't like this approach, but do this with ifdefs and create different versions of your shader to account for shadow/noshadow lights. You can cache them yourself and switch them at runtime in the CPU. It is better to do the branching in the CPU than in the GPU; keep in mind you will do this only once for the object, whereas in the GPU you will do that once for every pixel, which is very wasteful.
Something along the lines of
#if defined(USE_SHADOWS)
sampler2D [...]
#endif
Upvotes: 1