1

I have a C++ problem here which I simply cannot understand.

I have 2 slightly different functions. Both of them should do the very same thing. But only one works properly.

Method 1: input of the method is 'const string samplerName = "test"'


void setUniformSampler(Gluint program, const string samplerName, GLuint sampler) {
    GLint uniformLocation = glGetUniformLocation(program, samplerName.c_str()); // returns -1

    if(uniformLocation >= 0) {
        glUniform1i(uniformLocation, sampler);
    } else {
        throw exception(...);
    }
}

Method 2:


void setUniformSampler(Gluint program, GLuint sampler) {
    GLint uniformLocation = glGetUniformLocation(program, "test"); // returns 0

    if(uniformLocation >= 0) {
        glUniform1i(uniformLocation, sampler);
    } else {
        throw exception(...);
    }
}

As you can see, glGetUniformLocation returns 2 different values. The correct return value would be "0", not "-1". So I wonder, what exactly is the difference between the two calls?

quote: "c_str() generates a null-terminated sequence of characters (c-string) with the same content as the string object and returns it as a pointer to an array of characters". And that is precisely what the method glGetUniformLocation(...) needs as its second parameter. So, why does only Method 2 above succeed? Is it a compiler problem?

I'm working with MS Visual Studio 2008 on Win7.

I've been searching for this bug for almost 2 days now. I really want to clarify this. It drove me crazy...

Thanks Walter

EDIT:

This doesn't work either.


void setUniformSampler(Gluint program, const string samplerName, GLuint sampler) {
    const GLchar* name = samplerName.c_str();

    GLint uniformLocation = glGetUniformLocation(program, name); // still returns -1

    if(uniformLocation >= 0) {
        glUniform1i(uniformLocation, sampler);
    } else {
        throw exception(...);
    }
}

Walter
  • 396
  • 1
  • 5
  • 16
  • Are you sure the `samplerName` string actually contains `test`? Can you check with the debugger or a `printf()` call? – Frédéric Hamidi Dec 09 '10 at 06:22
  • Yes, I did use the debugger of Visual Studio and I can confim that samplerName contains test. – Walter Dec 09 '10 at 06:23
  • What about `program`? Is it correctly initialized/passed in the first case? – Frédéric Hamidi Dec 09 '10 at 06:31
  • It's not clear from your partial code, but it looks like you have two `samplerName` variables, one being a parameter of `setUniformSampler` and one being a global variable. Did you use the debugger to test that the one inside `setUniformSampler` has the value "test"? – JWWalker Dec 09 '10 at 06:41
  • There is no global variable. I maybe didn't make it very clear. The input of Method 1 is samplerName = "test". That's not supposed to be a global variable... – Walter Dec 09 '10 at 06:44
  • @Walter:If you change samplerName from `string` to `char *` does it work? I mean change the signature not assign to `char *`.According to docs `name` must not be component of vector and string is kind of sequence container. May be that creates some issue. Also are you sure the program compiles and links ok? – Cratylus Dec 09 '10 at 06:58
  • 2
    @Walter: samplerName does NOT simply contain test or this would work. There is no magic going on. You are making a mistake in your code. Check for spaces, for one. – Goz Dec 09 '10 at 07:36
  • Why not just make samplerName a const GLchar* to begin with? why does the input of the function absolutely have to be a string? – Ned Bingham Dec 09 '10 at 16:26
  • You should post the shaders also. – Dr. Snoopy Dec 10 '10 at 14:30

3 Answers3

0

Your parameter is const, and you can't call a non-const function on a const object. Maybe that's the problem? The function needs a pointer to a null-terminated string. Make sure that's what you're giving it.

jakev
  • 2,815
  • 3
  • 26
  • 39
  • I'm not sure if I understand you correctly. If I add "const GLchar* name = samplerName.c_str();" as the first call in Method 1 and call glGetUniformLocation(program, name), it doesn't work either. – Walter Dec 09 '10 at 06:28
  • try not making name a const variable. the const keyword guarantees the compiler that the variable won't be modified. If a function doesn't promise not to modify a variable by declaring its corresponding parameter as const (whether it actually does or not is a separate issue) then you can't pass a const variable to it. – jakev Dec 09 '10 at 06:35
  • GLchar* name = samplerName.c_str(). Like that? I'm afraid that leads to a compiler error, as c_str() returns a const char pointer. See http://www.cplusplus.com/reference/string/string/c_str/... – Walter Dec 09 '10 at 06:48
  • my mistake. glGetUniformLocation also takes a const pointer. I'm no expert on this, but maybe use char * cstr and strcpy (cstr, str.c_str()); (from the cplusplus.com example) and then pass in cstr? – jakev Dec 09 '10 at 07:02
  • the const here is irrelevant because he passes the parameter by value, which means the function takes a copy anyway. const string& would means something different. – t.g. Dec 09 '10 at 07:07
0

check the implementation and the type of the parameter in glGetUniformLocation(parameter), "test" is a const literal whose life and location never change in your executable's life, while c_str() is dynamically calculated from a string object, it dies when the string object dies.

In other words, you need to check in side of glGetUniformLocation()to find the reason, which I guess is related to some CRT string functions.

t.g.
  • 1,719
  • 2
  • 14
  • 25
  • It is likely to do with how that glGetUniformLocation scans the current shader program for a variable name. Like t.g. said, it may not allow strings inside your program which have a life span shorter than that of the executable. – jakev Dec 09 '10 at 07:28
  • JakeVA: You're wrong about that one. Think about it: glGetUniformLocation returns the uniform ID, so it must have fully processed the contents of the passed pointer upon return. There's no lazy evaluation going on here. My guess: Also the shader programm is defined as a static string, and depending on the compiler settings static strings may be of wide character, but string::c_str returns a simple ASCIIZ string. My hint: Debug again, but don't just look at the string display, but take a look at the actual byte sequence (hex edit view). – datenwolf Dec 09 '10 at 09:55
0

You might be victim to a mixup of wide character vs slim (i.e. 8-bit) character strings. If both your shader source and the uniform name are defined as static strings, then they will agree on the string representation. string::c_str might change this, as c_str will always return a string of char, i.e. it is not wchar aware.

Technically it should make difference, since a bug free shader compiler use a unambigous internal representation. But there may be a bug, that the difference between wide and slim characters are interpreted as different identifiers.

What happens if you pass the shader source, too through string::c_str? Also check the debugger hexedit view on the string variable. If it looks like this:

00000000  74 65 73 74 0a                                    |test.|

You got a 8-bit character string. If it looks like this:

00000000  74 00 65 00 73 00 74 00  0a 00                    |t.e.s.t...|

then you got a wide string. And then compare this with the variable in which the shader is supplied.

datenwolf
  • 159,371
  • 13
  • 185
  • 298
  • "as c_str will always return a string of char, i.e. it is not wchar aware". you are wrong here. basic_string<> is wchar_t aware. check here: http://msdn.microsoft.com/en-US/library/3372cxcy%28v=VS.80%29.aspx. string and wstring are distinct classes, it's very unlikely a string type, not wstring type, is used to hold something like "t.e.s.t..." in this case. – t.g. Dec 09 '10 at 13:10
  • I was referring to the c_str variant of std::string class. If you look at the beginning of the sentence you'd have seen I was talking about std::string::c_str, then just to lazy to write the full thing. And the OP specifically used that type (std::string) in his failing code. – datenwolf Dec 09 '10 at 16:27
  • we are agreeing on the same fact: string, not wstring, is used in the OP's code. But we differ in the implication of that usage. To me, it implies wide chars(whar_t) like '|t.e.s.t...|' are very unlikely contained in the string object. He would even meets with a problem earlier trying to assign those wide chars to the string object(samplerName) in the first place, as not many APIs are available for that purpose no matter what library he uses(STL, CRT etc.) . It's a safe bet for me that samplerName contains ASCII or UTF-8 chars. – t.g. Dec 10 '10 at 03:52
  • Yes indeed, this is what I say, too. But if the actual shader code comes from a static, i.e. not through a std::string but something else, then this may explain the problem binding the uniform by an identifier supplied through a std::string. – datenwolf Dec 10 '10 at 08:48