GLSL dilemma (in my Objective-C application)

Apprentice
Posts: 18
Joined: 2006.06
Post: #1
I have an application that I would like to add shader support for. It's fully "working" as of now.

When I try to add a shader, the application runs just fine, but it seems that the shader I specify is not used! Now, how come?

This is how I setup my shaders:

Code:
- (void)setShaders
{
    // Create our shader objects.
    vertexShader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
    fragmentShader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
    
    // Temporary variables for checking compiling/linking.
    GLint vertexCompiled;
    GLint fragmentCompiled;
    GLint shadersLinked;
    char str[4096];
    
    // Our shaders resident in the following two strings. Convert them to char
    // arrays since OpenGL wants it in when setting shader sources.
    const char * ff = [fragmentShaderTextFile cString];
    const char * vv = [vertexShaderTextFile cString];
    
    // Set the shaders source codes.
    glShaderSourceARB(vertexShader, 1, &vv, NULL);
    glShaderSourceARB(fragmentShader, 1, &ff, NULL);
    
    // Compile the shaders.
    glCompileShaderARB(vertexShader);
    glCompileShaderARB(fragmentShader);    
    
    // Get compiling status.
    glGetObjectParameterivARB(vertexShader, GL_OBJECT_COMPILE_STATUS_ARB, &vertexCompiled);
    glGetObjectParameterivARB(fragmentShader, GL_OBJECT_COMPILE_STATUS_ARB, &fragmentCompiled);
    
    // Before we continue, check for compiling errors.
    if(!vertexCompiled || !fragmentCompiled)
    {
        if(!vertexCompiled)
        {
            glGetInfoLogARB(vertexShader, sizeof(str), NULL, str);
            NSLog(@"Vertex shader compile error:");
            NSLog(@"%s", str);
        }
        
        if(!fragmentCompiled)
        {
            glGetInfoLogARB(fragmentShader, sizeof(str), NULL, str);
            NSLog(@"Fragment shader compile error.");
            NSLog(@"%s", str);
        }
        
        NSLog(@"Since the shader(s) were not compiled correctly, I won't try linking at all.");
    }
    
    // No compiling errors, ready to link the shader objects into a program.
    else
    {
        NSLog(@"Shaders compiled OK.");
        
        // Create the program object.
        programShader = glCreateProgramObjectARB();
        
        // Attach the shaders to the program.
        glAttachObjectARB(programShader, fragmentShader);
        glAttachObjectARB(programShader, vertexShader);
        
        // Link program.
        glLinkProgramARB(programShader);
        
        // Get linking status.
        glGetObjectParameterivARB(programShader, GL_OBJECT_LINK_STATUS_ARB, &shadersLinked);
        
        // Print error log.
        if(!shadersLinked)
        {
            glGetInfoLogARB(programShader, sizeof(str), NULL, str);
            NSLog(@"Program object linking error.");
            NSLog(@"%s", str);
        }
        
        else
        {
            // Detach the shaders so that they automatically get's deleted once
            // we delete the program at application termination.
            // IMPLEMENT!
            
            NSLog(@"Shaders linked OK.");
        }
    }
}

When I want to use it, inside my display function, I simply call:

Code:
glUseProgramObjectARB(programShader);

some_code_that_draws_things();

glUseProgramObjectARB(0);

I have tried even the simplest shaders that change the color of all vertices, but nah, it doesn't seem to work... and compiling/linking status says "compiled/linked OK" (the output from my NSLog's above).

Anyone got a clue on how to go on from here?
Quote this message in a reply
Moderator
Posts: 1,140
Joined: 2005.07
Post: #2
In order to actually use the shaders, you need to use glEnable and glDisable with GL_VERTEX_SHADER_ARB and GL_FRAGMENT_SHADER_ARB. (for the ones you're using)
Quote this message in a reply
Apprentice
Posts: 18
Joined: 2006.06
Post: #3
akb825 Wrote:In order to actually use the shaders, you need to use glEnable and glDisable with GL_VERTEX_SHADER_ARB and GL_FRAGMENT_SHADER_ARB. (for the ones you're using)

Are you sure about that? I *just* tried to move my "[self setShaders]" to right before the actual rendering, and that made my day; now it works just perfect.

Maybe I ran that piece of code TOO early? Huh
Quote this message in a reply
Apprentice
Posts: 18
Joined: 2006.06
Post: #4
My shaders run fine as of now, but the CPU is choking when they're activated; I thought that the GPU would take care of this?

Example: No shader activated - 5 % (total CPU)
Example: Shader activated - 55 % (total CPU)

What does this indicate? That I have a *very* complex shader, or is something else wrong?
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #5
Probably that the shader is too complex for your hardware -- potentially because your hardware doesn't support shaders at all.

Code:
#if defined(__APPLE__)
    glUseProgramObjectARB(shader->program);

    long hardwareAccelerated;

    CGLGetParameter(
        CGLGetCurrentContext(),
        kCGLCPGPUVertexProcessing,
        &hardwareAccelerated);
    if (!hardwareAccelerated)
    {
        fprintf(stderr,
            "Warning: Vertex shader is NOT being hardware-accelerated\n");
    }
    CGLGetParameter(
        CGLGetCurrentContext(),
        kCGLCPGPUFragmentProcessing,
        &hardwareAccelerated);
    if (!hardwareAccelerated)
    {
        fprintf(stderr,
            "Warning: Fragment shader is NOT being hardware-accelerated\n");
    }

    glUseProgramObjectARB(0);
#endif
Quote this message in a reply
Apprentice
Posts: 18
Joined: 2006.06
Post: #6
Hm, I got the MacBook Pro (2.16 GHz, X1600 with 256 MB) so it shouldn't be a problem right?

I tried your code, and it seems that my hardware IS running the shader...

Is there any possibility that some of the functions (like step(), distance() etc.) are implemented in a strange way that makes the shader take way too long time?
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #7
That hardware certainly should be more than sufficient for most shaders.

Your next stop is Shark. It'll tell you where you're spending your CPU time.
Quote this message in a reply
Apprentice
Posts: 18
Joined: 2006.06
Post: #8
OneSadCookie Wrote:That hardware certainly should be more than sufficient for most shaders.

Your next stop is Shark. It'll tell you where you're spending your CPU time.

Thanks for the tip! I tried playing with the GLSLShowpiece demo that came along with Xcode, and with some of those demos, the CPU certainly does show the same results - like running at 50 %... Blink

I thought that the CPU wasn't involved in GPU activity at all; if the shader is complex, the CPU wouldn't peak... it would just have to wait with it's next instruction until the shader is done?
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #9
The CPU is still being used to stream vertices, textures etc -- though obviously depending on the context.
Quote this message in a reply
Apprentice
Posts: 18
Joined: 2006.06
Post: #10
TomorrowPlusX Wrote:The CPU is still being used to stream vertices, textures etc -- though obviously depending on the context.

Ok... seems reasonable! I think I've narrowed it down to the following (see my fragment shader code first):

Code:
// Lightcone specific attributes.
uniform vec3 position, lookInDirection;

uniform sampler2D depthMapFront, depthMapBack;
uniform sampler2DShadow shadowMap;
// IMPLEMENT THIS - uniform sampler2D gobo;
uniform int depthMapSize, shadowMapSize;

uniform mat4 shadowMapMatrix;
uniform float intensityCone;
uniform float redValueCone, greenValueCone, blueValueCone;
uniform float linearAttenuation, quadraticAttenuation;

// Object specific attributes.
uniform float specularObject, shininessObject;
uniform int showShadowHoles;

// Scene specific attributes.
uniform float intensityScene;
uniform float fogIntensity;
// IMPLEMENT THESE - uniform sampler2D noiseMap1, noiseMap2;
// IMPLEMENT THIS - uniform float angle


varying vec4 vertexPosition;
varying vec3 vertexNormal;
varying vec3 lightDirection;
varying vec4 shadowCoord;


// Front and back texture values.
float texture_front;
float texture_back;


float isCurrentPointInShadow(in vec3 c);
float isCurrentPointInSideCone(float currentZ);


void main()
{
    // The number of steps in the loop. The more steps, the better the quality...
    int stepsInLoop = 60;
    float stepsInLoopScale = 1.0 / float(stepsInLoop);

    // Z-value of the current fragment.
    float currentZ = gl_FragCoord.z;

    // Initialize the distance from lightsource to current point along the ray.
    float distancePPP = 0.0;

    // Create copy of the current vertex position since it's write protected.
    vec4 rayVector = vertexPosition;    
    
    // The lenght of the interval one steps between each of calculation of
    // the ray between the eye and the current point in the scene.
    float zStep = currentZ / float(stepsInLoop);

    // Vector, divided in interval, depending on number of steps in loop.
    vec3 stepVector = vertexPosition.xyz / float(stepsInLoop);
    
    // Shadowmap texture coordinates
    vec3 projCoord = 0.5 * (shadowCoord.xyz / shadowCoord.w + 1.0);
    
    // Texture coordinates of depthmaps.
    vec2 tex = gl_FragCoord.xy;
    
    // Normalize with the depth map size since the depth map values span [0,1]
    // and the windows coords span [1, depthMapSize]
    tex.x /= float(depthMapSize);
    tex.y /= float(depthMapSize);
    
    // Set front and back texture values.
    texture_front = texture2D(depthMapFront, tex).x;
    texture_back = texture2D(depthMapBack, tex).x;

    //texture_front*= (step( abs(texture_back-texture_front), 0.0001 ) );
    // noise map coordinates
    /*
    vec2 noiseTex = gl_FragCoord.xy/256.0;
    noiseTex.x+=  angle*0.01; // rotate smoke x-wise
    noiseTex.y+=  -angle*0.004; // rotate smoke y-wise
    */
    
    // value 1.0 or 0.0 depending if pixel is inside or outside lightcone
    float isInsideOfCone = isCurrentPointInSideCone(currentZ);
    
    // Dot products.
    float NdotL, NdotHV;

    // The color of the scene objects (like walls, ceiling etc.).
    vec4 sceneColor;

    // Total attenuation, based on the linear and quadratic attenuation for the cone.
    float attenuation;

    float compareValues, spotEffect; // angles

    vec3 n, halfV, goboProjCoord, volumeShadowCoord, lightVec; // normalize normal and halfVector again. No need to normalize lightVector again.
    vec4 volumeCoord, lightColor, volumeColor, surfaceColor;
    
    
    
    // Raycasting loop    
    for(int i = 0 ; i <= stepsInLoop ; i++)
    {
        // Create projection coordinates for "lightholes" and gobo coordinates.
        volumeCoord = shadowMapMatrix * rayVector;
        
        // Normalize the volume shadow coordinates so that they're between 0 and 1.
         volumeShadowCoord = 0.5 * (volumeCoord.xyz / volumeCoord.w + 1.0);
        
        // Update.
        distancePPP = distance(rayVector.xyz, position);
        
        // Attenuation.
        attenuation = distancePPP * (linearAttenuation + quadraticAttenuation * distancePPP);
        
        // Check if pixel is in within lightcone, shadow or not (0 or 1), multiply with GOBO color,attenuation and scale
        volumeColor.rgb += isCurrentPointInSideCone(currentZ) / attenuation;// * isCurrentPointInShadow(volumeShadowCoord);
                    
        rayVector.xyz -= stepVector; // step further away along ray in eye-coords
        currentZ -= zStep;  // step further away along ray in win-coords
    
    }
    
    
    
    // Volume color is an RGB channel that coll
    volumeColor *= stepsInLoopScale * vec4(redValueCone, greenValueCone, blueValueCone, 1.0); //*texture2D(noiseMap1,noiseTex)*texture2D(noiseMap2,noiseTex);

    // fragment shader can´t write a varying variable, hence need to create a new normal variable
    n = normalize(vertexNormal);
    
    // Compute the cos of the angle between the normal and lights direction.
    // The light is directional so the direction is constant for every vertex.
    // Since these two are normalized the cosine is the dot product. We also
    // need to clamp the result to the [0,1] range.
    NdotL = max(dot(n, normalize(lightDirection)), 0.0);

    // Ambient (diffuse) scene color.
    // WHY IS THIS "+=" instead of "="? It runs once, no?
    sceneColor += gl_Color * NdotL;
    
    // Color of all surfaces which the lightcone hit.
    surfaceColor = isInsideOfCone * volumeColor * NdotL;
        
    // for pixels inside lightcone, calculate specular too
    if(isInsideOfCone == 1.0)
    {
        // IS THIS THE RIGHT FORMULA???
        halfV = normalize(vec3(0.0, 2.0, -2.0)) + normalize(position);

        NdotHV = max(dot(n, halfV),0.0);
        surfaceColor += volumeColor * specularObject * pow(NdotHV, shininessObject); //color of cone * specularity
    }
        
    //gl_FragColor = (surfaceColor * isCurrentPointInShadow(projCoord) * 0.5 * intensityCone) + (sceneColor * intensityScene) + (volumeColor * intensityCone * fogIntensity);
    //gl_FragColor = isInsideOfCone * vec4(1.0, 1.0, 1.0, 1.0);
    gl_FragColor = isInsideOfCone * (surfaceColor+ sceneColor); // + volumeColor

}

// shadow lookup function - implemented with Percentage Closer Filtering - too heavy to use though
float isCurrentPointInShadow(in vec3 c)
{
        
    float mapScale = 1.0 / float(shadowMapSize);
    float shadowColor = shadow2D(shadowMap, c).r;

//    shadowColor += shadow2D(shadowMap, c + vec3( mapScale,  mapScale, 0)).r;
//    shadowColor += shadow2D(shadowMap, c + vec3( mapScale, -mapScale, 0)).r;
//    shadowColor += shadow2D(shadowMap, c + vec3( mapScale, 0, 0        )).r;
//    shadowColor += shadow2D(shadowMap, c + vec3(-mapScale,  mapScale, 0)).r;
//    shadowColor += shadow2D(shadowMap, c + vec3(-mapScale, -mapScale, 0)).r;
//    shadowColor += shadow2D(shadowMap, c + vec3(-mapScale,  0, 0       )).r;
//    shadowColor += shadow2D(shadowMap, c + vec3(        0,  mapScale, 0)).r;
//    shadowColor += shadow2D(shadowMap, c + vec3(        0, -mapScale, 0)).r;
//    shadowColor = shadowColor / 9.0;

    // Return shadowColor or 1.0 (shadows off)
    return step(float(showShadowHoles), shadowColor);
}

float isCurrentPointInSideCone(float currentZ)
{
    //return 1.0;
    return step(currentZ, texture_back) * step(texture_front, currentZ);
}

Look into the RAYCASTING LOOP... There is the following line:

Code:
        volumeColor.rgb += isCurrentPointInSideCone(currentZ) / attenuation;// * isCurrentPointInShadow(volumeShadowCoord);

Comment that line and.... SWOOOSH! The application goes from 1 FPS to 60 FPS...

How come... have I missed something fundamental? Like GLSL thinking that it is way more work to add stuff to current variables than to new ones?
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #11
That's really odd. It looks like that call resulted in CPU rather than GPU execution. My crapulent 5200 runs that code unmodified at full speed on GPU...
Quote this message in a reply
Apprentice
Posts: 18
Joined: 2006.06
Post: #12
TomorrowPlusX: Thanks, that's just what I thought...

...but this is still really strange. And since I'm a newbie I really don't know how to go on from here. Do you guys have any suggestions?
Quote this message in a reply
Apprentice
Posts: 18
Joined: 2006.06
Post: #13
arrelid Wrote:TomorrowPlusX: Thanks, that's just what I thought...

...but this is still really strange. And since I'm a newbie I really don't know how to go on from here. Do you guys have any suggestions?

It seems like if I do operations with the plus operator ("+") inside the loop, the fragment shader turns into mustard... IT GOES SOOO SLOW! However, just for fun, I tried to switch the "+" against "*" (the times operator) and swoosh; it's fast again. Is plus harder for the GPU than times?
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #14
Er... I just wanted to say I thought the offending code posted above was from the GLSLShowpiece, not your own work -- I can't say that your own work works on my 5200.

Anyway, it's not at all uncommon for some odd little bit like you've described to cause a software fallback. There's a lot of discussion about that on apple's mac-opengl mailing list. You ought to post this code there, as well as a bug-report. Apple's GLSL compiler has some rough edges.
Quote this message in a reply
Sage
Posts: 1,234
Joined: 2002.10
Post: #15
Try running your shader in GLSLEditorSample which comes with Xcode 2.3. It will tell you in the preview window if you fall back to SW while you interactively edit the code.
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  GLSL or Cg in 3D graphics application for Mac OS X pileofnuts 3 3,308 Oct 16, 2008 12:29 AM
Last Post: Bachus
  GL_DEPTH_TEST dilemma Wheatie 8 5,685 Sep 28, 2004 08:26 AM
Last Post: NYGhost