Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Page 2 of 3 FirstFirst 123 LastLast
Results 11 to 20 of 21

Thread: shader source names

  1. #11
    Senior Member OpenGL Guru
    Join Date
    May 2009
    Posts
    4,948
    Why should that information not be made accessible?
    For the same reason you can't get a list of all buffer objects. Or a list of all texture objects.

    You are expected to take certain responsibilities on for yourself. And this includes keeping track of what you have actually done with the system.

    That apart from the need to delete the named strings once everything got compiled.
    How do you delete your buffer objects after you're finished using them? How do you delete your textures after you're done with them?

    If writing a module concerned with shader stuff one might not necessarily know what sources were loaded. That information would eiher have to be passed to the module by the user or can be queried.
    If I'm writing a module that has dependencies on what someone else has done, then if they haven't done it yet, they deserve to get broken behavior. Garbage in, garbage out.

    And personally, I would say that a module that is that dependent on the specific initialization someone else did is bad design. If the module needs certain things to be loaded, then it should be responsible for loading them.

    Also, I think you're getting somewhat confused with the notion of how these things work. The point of the #include mechanism is that you don't need to build string prefixes and so forth when you use glShaderSource/glShaderProgram. You just pass a single string, which #includes what it needs. The C/C++ code should neither know nor care about what any particular shader #includes.

    So I don't see why any C/C++ code would ever care one way or the other. It's up to the various shader strings to know where their stuff is, and it's up to whoever sets up the library of includes to put them together.

  2. #12
    Junior Member Regular Contributor
    Join Date
    Nov 2012
    Location
    Bremen, Germany
    Posts
    167
    For the same reason you can't get a list of all buffer objects. Or a list of all texture objects.
    You are expected to take certain responsibilities on for yourself. And this includes keeping track of what you have actually done with the system.
    That mainly cites the state as it is - but why should that be that way? There must be a reasoning behind the decision NOT to expose that information. That information has to be present in the library - otherwise one could not query for the existence of named string. And this also applies to buffer and texture objects now that you say it. It's a poor design decision not to make them enumerable.

    How do you delete your buffer objects after you're finished using them? How do you delete your textures after you're done with them?
    Are you really asking this or do you take me for a fool? I don't delete them at all - the OS does this when I exit the program.

    If the module needs certain things to be loaded, then it should be responsible for loading them.
    Not necessarily.If all the module should do is to realize a transition from system-state A to state B then it is poor that information has to be passed to it at all. The system state should be well-defined in itself.

  3. #13
    Senior Member OpenGL Guru
    Join Date
    May 2009
    Posts
    4,948
    That mainly cites the state as it is - but why should that be that way?
    Why... shouldn't it be that way? Consider what you're asking.

    What good is it to get a list of buffer objects? What exactly would you *do* with that? What exactly could you do with that? You could enumerate them and get some generic info about them (size, etc). You could enumerate them and get their data. But since you don't know anything about them, you have no idea what to do with them. Modifying them in any way, without knowing what they're for, would be exceedingly dangerous.

    The same goes for any OpenGL object that you don't already have a reference to. The only reason it makes the slightest bit of sense for include strings is that strings are named, and the name could have some intrinsic meaning. Or that you might be putting together some shader from parts, and you're using whether or not a particular named string exists to decide which to include. No wait, we can already check for a specific named string, so that's not a use case.

    The only thing you could want to do with enumerating objects is to spit them out to a log of them for debugging purposes. And quite frankly, that's best done in a tool like glIntercept.

    Are you really asking this or do you take me for a fool? I don't delete them at all - the OS does this when I exit the program.
    I'll leave it to you to decide the wisdom of having an explicit policy of not cleaning up resources. What I'm curious about is this: if you're content with just dropping all of your objects on the floor at the end of the program, why do you suddenly feel the need to clean up shader strings? Why are they more special than buffers, textures, and other things that consume actual GPU resources?

    You have not presented a compelling use case for wanting to query the list of shader strings besides wanting to do it. What kind of system are you making where doing this is essential? Provide details.

  4. #14
    Junior Member Regular Contributor
    Join Date
    Nov 2012
    Location
    Bremen, Germany
    Posts
    167
    The lack of a specific sense of humor aside, a compelling use-case is hard to find. It is not that lists could not be kept by the application. It is not that the gl could not be defined to make them queryable. My feeling is that any state-variable that influences the behaviour of the system should be queryable.

  5. #15
    Member Regular Contributor
    Join Date
    Jan 2011
    Location
    Paris, France
    Posts
    250
    I think exactly the same thing => "any state-variable that influences the behaviour of the system should be queryable"
    (but ok, this can be effectively very dangerous if an application can too read [and/or write] alls or parts of state-variables that are generated/used by another(s) application(s) ...)

    Note that this can be handled by an external library for to handle the ID/string name conversion/storing using a securised sharing of them between applications
    (this can certainly to be implemented using something like semaphores and shared segments)

    But an external library cannot to be used for to automaticaly handle the include of the content of an "named ID object" into another at the language level
    (because this is the driver/opengl library that have to handle this ...)
    Last edited by The Little Body; 02-18-2013 at 06:44 PM.
    @+
    Yannoo

  6. #16
    Junior Member Regular Contributor
    Join Date
    Nov 2012
    Location
    Bremen, Germany
    Posts
    167
    This comes back to the initial issue: One can write a simple pre-processor that takes a source-file, seaches for include-statements and generates a shader by using multiple source-buffers when calling ShaderSource - one for each file. That is, there is a mapping between source-file-names and the integers usually indicated by __FILE__. But substituting the source-names into the info-log cannot be done - at least with core functionality - in a safe way as the formatting of the logs is driver dependent.

    As for the state-variables and the NamedString-extension this is half-true: It's not the inter-application-border what I'm concerned with. It is about the reusability of code outside of it's originary Environment.
    One could - as an example - write a function that generates mip-maps using a special kind of scaling-algorithm for all textures with certain properties. This function could be called from the application without supplying any arguments. What would be needed for it was the ability to query the list of existing textures from the API. As the API is defined now that list has to be passed to the function, which is - of course - no Problem: It just makes, under certain circumstances, the reformatting of the application-side lists of textures necessary to supply them in the form the function takes them.
    For the named strings one can easily imagine the workflow of a typical application using shaders:
    The context gets set up, shader sources are read and compiled and then the main-Loop starts.
    Being able to query for the existence of named strings and an additional type, namely SHADER_SOURCE, an application could read in all sources and includes without keeping it's own list of files that were read in, then compile all SHADER_SOURCE strings just keeping a list of compiled shaders with their Name, and after compilation free all named strings. Steps two and three could be done in a general, reusable way, This can - again - easily be realized by shifting the list-keeping to the user of the api.
    It is half-true because a function taking the things to be processed argument is more-reusable in scenarios where some objects are to be kept out. That is a function
    GenerateMissingMipMaps(GLuint* textures, GLuint count) is more generic as the simple GenerateMissingMipmaps() which would need to query the list from the glAPI. On the other hand it would safe the work of iterating through the application-side list of textures and building a GLuint* from it.

  7. #17
    Senior Member OpenGL Guru
    Join Date
    May 2009
    Posts
    4,948
    One could - as an example - write a function that generates mip-maps using a special kind of scaling-algorithm for all textures with certain properties. This function could be called from the application without supplying any arguments.
    Why would you want to write a function like that? Generally speaking, programmers consider global variables to be bad programming practice. Programmers generally prefer that if you're going to call a function on some parameters, that you actually pass those parameters to the function. Global variables put all of the power in the library, which is not what people want. They want direct control over what the library does.

    You wouldn't want glGenerateMipmap to iterate through all of the textures and generate mipmaps based on some heuristic.

    And from a completely practical perspective... what if you want to do this more than once? Like you're doing some texture generation or render-to-texture operation, and you want to apply this to a specific texture which has been modified since the last time this operation was done? Well, you'd need a function that you could call on a specific texture.

    And most importantly of all, any real application is going to have to have a list of loaded resources anyway, so that it can properly unload them.

    GenerateMissingMipMaps(GLuint* textures, GLuint count) is more generic as the simple GenerateMissingMipmaps() which would need to query the list from the glAPI. On the other hand it would safe the work of iterating through the application-side list of textures and building a GLuint* from it.
    This would save nothing. You'd just be iterating through the OpenGL-side list of textures and culling from them certain specific ones to modify. In either case, you're iterating over a list. The only thing you might save is having to build an array. And even that isn't truly essential, since you can just repeatedly call the function with each texture individually as you find it.

    The context gets set up, shader sources are read and compiled and then the main-Loop starts.
    Being able to query for the existence of named strings and an additional type, namely SHADER_SOURCE, an application could read in all sources and includes without keeping it's own list of files that were read in, then compile all SHADER_SOURCE strings just keeping a list of compiled shaders with their Name, and after compilation free all named strings. Steps two and three could be done in a general, reusable way, This can - again - easily be realized by shifting the list-keeping to the user of the api.
    So what you want is this:

    Code :
    for(std::string filename : directory)
    {
      std::string loadedFile = readTextFile(filename);
      glApplyShaderString(filename.c_str(), loadedFile.c_str());
    }
     
    std::map<std::string, GLuint> shaderList;
     
    for(const GLchar *name : glGetStringList)
    {
      const GLchar *loadedFile = glGetNamedString(name);
      GLuint shader = glCreateShader(...);
      glShaderSource(shader, 1, &loadedFile, NULL);
      glCompileShader(shader);
      //Error check.
      shaderList.push_back({name, shader});
    }

    So why not just do this?

    Code :
    std::map<std::string, std::string> loadedStrings;
     
    for(std::string filename : directory)
    {
      std::string loadedFile = readTextFile(filename);
      loadedStrings.push_back({filename, loadedFile});
    }
     
    std::map<std::string, GLuint> shaderList;
     
    for(const auto &loaded : loadedStrings)
    {
      GLuint shader = glCreateShader(...);
      const GLchar *loadedString = loaded.second.c_str();
      glShaderSource(shader, 1, &loadedString, NULL);
      glCompileShader(shader);
      //Error check.
      shaderList.push_back({loaded.first, shader});
    }

    What do you gain by forcing OpenGL to be able to enumerate the active objects that you can't get from this?

  8. #18
    Member Regular Contributor
    Join Date
    Apr 2004
    Posts
    251
    Quote Originally Posted by hlewin View Post
    That mainly cites the state as it is - but why should that be that way? There must be a reasoning behind the decision NOT to expose that information. That information has to be present in the library - otherwise one could not query for the existence of named string. And this also applies to buffer and texture objects now that you say it. It's a poor design decision not to make them enumerable.
    It is not common practice for APIs to provide the user with a list of all objects he has created so far. For example, you can't query about which are all open files your process currently hold (well, there is a way to do that on linux but its linux-specific). Or you cant ask about all malloc-ed bocks.

    Basically it is a matter of balance between simplicity and the functionality of the API and it's possible implementations. Its the question about how much do we gain against how much do we lose.
    From these queries we gain too little because they are very very rarely needed (and the application could keep track of this info if it really needs it), while we lose in terms of more complex API/implementation.
    Generally it is considered that such queries are not worth the trouble.
    While it is generally true that this information should be present in the system, it may not be very easy to collect and convert to suitable for presentation form.

  9. #19
    Junior Member Regular Contributor
    Join Date
    Nov 2012
    Location
    Bremen, Germany
    Posts
    167
    You wouldn't want glGenerateMipmap to iterate through all of the textures and generate mipmaps based on some heuristic.
    Why not - if the operation is well-defined? It is even another case if implementing such a function - just read on.

    This would save nothing.
    No, no, no. You don't understand me. That would save me work!

    The only thing you might save is having to build an array. And even that isn't truly essential, since you can just repeatedly call the function with each texture individually as you find it.
    Maybe, maybe not. Maybe I want the MipMaps to be generated by a separate thread when there is nothing better to do.

    for(std::string filename : directory)
    {
    std::string loadedFile = readTextFile(filename);
    loadedStrings.push_back({filename, loadedFile});
    }
    That would introduce another parameter to the interface. The part of the first code block that generates the shaders would only require one variable to communicate to the rest of the application: shaderList. In the second code block it requires two. The more complex the interfaces between parts of the program get the more likely are Errors and the more difficult are they to be (re-)used in other Environments. The shaderList-variable - let it be an argument - is one example: If the code-block was to be reused in a plain-C program it would have to be changed.
    I do not know about other users but I generally look at 'official' APIs as building-blocks that can be relied on not to change, to be available across different environments and so forth. I would always prefer to make use of the gl-listkeeping-functions instead of the Interfaces I define myself.

  10. #20
    Senior Member OpenGL Guru
    Join Date
    May 2009
    Posts
    4,948
    No, no, no. You don't understand me. That would save me work!
    It only saves you work because you're not writing a real application. Most real applications already have lists of objects because they will need to explicitly release them at some point. This is part of why C doesn't provide a function to iterate over all allocated blocks of memory. It's part of why C++ doesn't provide a way to iterate over all new'd objects of a particular type.

    OpenGL should not be designed to make writing demo applications easier.

    Maybe I want the MipMaps to be generated by a separate thread when there is nothing better to do.
    And what's preventing you from simply passing the list of objects to the separate thread? At least there, you can wrap it in a proper mutex, so that accessing it will be reasonable. Unlike any OpenGL API, which likely will be fraught with undefined behavior if the other thread happens to create a new object while you're iterating.

    The part of the first code block that generates the shaders would only require one variable to communicate to the rest of the application: shaderList.
    No, it requires two variables. One of them is just hidden from sight. If you change the OpenGL context to a different, non-shared one, the function won't work. If you set no context to be current, the function won't work.

    Just because you didn't explicitly put one in the parameter list doesn't mean that it doesn't use other data. At least with the two parameter version, the user can see exactly what the function operates on.

    The more complex the interfaces between parts of the program get the more likely are Errors and the more difficult are they to be (re-)used in other Environments.
    Now you're making my point for me. Global interfaces are inherently more complex and more error prone than interfaces that take objects directly. They have implicit parameters that are not visible. Just ask any one who does test-driven development; writing tests for objects and functions that use globals is much more difficult than for functions which don't.

    This is one of the primary reasons behind the desire to move OpenGL to DSA-style interfaces: to turn implicit global parameters into explicit parameters.

    I do not know about other users but I generally look at 'official' APIs as building-blocks that can be relied on not to change, to be available across different environments and so forth.
    If you truly like implicit global parameters that much, you could make one yourself. You could even wrap the interface in C calls, so that it "can be relied on not to change, to be available across different environments".

    There's nothing special about OpenGL that you need it to provide this functionality for you.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •