rimsky
rimsky

Reputation: 1193

What are the SKShader requirements for accessing a uniform?

I have never encountered such inexplicable behavior as shown below for not using a defined variable. The code resulted from painstakingly boiling down a large program to the bare minimum needed to manifest the problem.

The following code in my SKScene creates three sprites and displays one, but uses a shader to display the texture of one of the other sprites that's passed in as a uniform.

    SKSpriteNode *background = [[SKSpriteNode alloc] initWithImageNamed:@"background"];
    SKSpriteNode* piece1 = [[SKSpriteNode alloc] initWithImageNamed:@"piece1"];
    SKSpriteNode *piece2 = [[SKSpriteNode alloc] initWithImageNamed:@"piece2"];

    SKShader* shader = [SKShader shaderWithFileNamed:@"test.fsh"];
    [shader addUniform:[SKUniform uniformWithName:@"u1" texture:background.texture]];
    [shader addUniform:[SKUniform uniformWithName:@"piece1Texture" texture:piece1.texture]];
    [shader addUniform:[SKUniform uniformWithName:@"u2" float:0.0]];
    [shader addUniform:[SKUniform uniformWithName:@"u3" float:0.0]];

    piece2.shader = shader;
    [self addChild:piece2];

Here's the shader:

void main(void) {
    gl_FragColor = texture2D(piece1Texture, v_tex_coord);
}

Instead of showing piece2, the shader should show piece1. However, it actually shows the background (from the unused "u1" uniform). This is true for both device and simulator.

[Umm, okaaaay....]

If I change the names of the unused uniforms, or change the order of the uniforms, or remove one of the unused uniforms, the shader works as expected.

[Really?]

Furthermore, after playing around with various names, I found names that once failed but later succeeded.

[sigh]

In the SKShader docs, there is this perplexing comment about adding uniforms to a shader:

The uniform must be accessed in the fragment shader.

This sounds very odd to me. Why is this true and what does this mean? In my real shader, I have uniforms that may not be accessed due to if-conditions and user behavior.

Is that okay? Or, do I need to artificially access every uniform just in case some wouldn't be accessed?

I understand that the SKShader doc is "a preliminary document" but the behavior is so unexpected, I can't help but wonder if there needs to be more explanation. Is this a SpriteKit issue, or does this hold true for OpenGL ES in general?

Upvotes: 5

Views: 930

Answers (1)

rimsky
rimsky

Reputation: 1193

I filed a bug (#20629165), as recommended by technical support.

Me: "Why must the uniform be used in the fragment shader? What will happen if a uniform isn't used?"

Apple: "The reason is for efficiency, if the uniform is declared but not used in the shader source, Sprite Kit will still perform shader uniform value upload to the GPU for the current draw. That being said, if a uniform is declared but not used, the result should still be correct. I encourage you to file a bug: https://developer.apple.com/bug-reporting/"

Upvotes: 1

Related Questions