Would you use shader debugging if it was available?

Would you?
The GLSL development in Mesa 3-D is going to be finished in a matter of one, maybe two months.
I realize that it wont be super-fast, but would you use Mesa to develop shaders if it had a nice extension allowing third-party apps execute the shader’s code step-by-step and watch variables contents in between?
If yes, what functionality would you expect it to have?

Great ! :slight_smile:
A software implementation of GLSL would be great to run shaders without risking crashing the machine because of beta drivers, allowing to debug code, trace variables values, etc.

I would really like ability to step through a pixel shader on a user selected pixel.

Would be cool to add such features right in ShaderDesigner !

Other stuff that’s not explicitly used in a shader for example screen x & y will probably be of interest.

Wow… just Wow, I never expected Mesa to implement GLSL…

If I had to choos a debug API this is kinda what I would want:

glShaderDebugBegin(GLenum shadertype, uint programID);
//Resets the debug state and begins the debugging, All standard GL calls are invalid between the Begin/End();

void glSetShaderDebugValue(GLenum variable_Type, T value);
//Sets variables for the debug state (ie. the current processing vertex for vertex shaders/ the current pixel coordinate for fragment shaders)

glShaderDebugDrawElements(…)
// Same as glDrawElements?Range? but does no rendering, will progress through shaders a line at a time on calls to glGetShaderDebugNextLine();
// Must have the debug vertex number or pixel coordinate before this is called
// All render calls between a shader debug section does not actually ‘render’, they are just called for debugging.
//(This is so we can debug the shader multiple times without worring about if the frame buffers have changed etc)

GLint glGetShaderDebugNextLine();
//Gets the next line number that the shader is currently up to. This is expected to be called continuiously until -1 is returned. (when the shader is complete or data is not set)

void glGetShaderDebugValue(GLenum variable_type, T *retValue);
//Gets info from the debug state. Similar values like the GLSL query interface. Values to:
// - Get the number of active variables
// - Get active variable x’s type
// - Get active variable x’s value

glShaderDebugEnd(); //Ends the debug state

Psudo example usage:

//Start debugging program 1's vertex shader
glShaderDebugBegin(GL_VERTEX_SHADER, 1);

//Debug vertex number 10
glSetShaderDebugValuei(GL_SD_VERTEX_NUMBER, 10); 

//Dummy render start
glShaderDebugDrawElements(GL_TRIANGLES, 20, GL_UNSIGNED_SHORT, indices);

//Loop while still on a valid line
int currLine = glGetShaderDebugNextLine();
while(currLine  != -1)
{
  //If the line is a line with a breakpoint
  if(IsBreakPointLine(currLine))
  {
    //Get the number of active variables
    GLuint numVars=0;
    glGetShaderDebugValuei(GL_SD_NUM_ACTIVE_VARIABLES, &numVars)
    
    //Loop for all active variables
    for(uint i=0; i<numVars; i++)
    {
      //Get variable type
      glGetShaderDebugValue(...);

      //Get variable value
      glGetShaderDebugValue(...);
    }

    //Update UI with new values (does not return until user gotos next line)
    UpdateDebugUI(...):
  }

  //Get the next line  
  currLine = glGetShaderDebugNextLine();
}

glShaderDebugEnd();

  

Hello,
I’m the author of the Shader Designer, and I have one or two thing to say about this topic. First, I must apologize, because I said that Shader Designer (or it’s successor) will have in the near future a GLSL debugger. Well, currently we can’t write the debugger for the Shader Designer. It is a very BIG task for only two guys (I’m not looking for more people to work in) that work for free. As said in another thread, we’ve already started the successor of the Shader Designer (will be a commercial tool), and the debugger module will have to wait until we convince some investors that our product worths (we want to live of our products, that’s why we’ve created TyphoonLabs), but the announcement of the MESA debugger will change a bit our plans :wink:

But we will be very pleased to include a software path for GL rendering in the Shader Designer in order to include the MESA’s GLSL debugger, when be finished, and we offer our collaboration to MESA GLSL dev team to help in the debugger design/implementation.

Here you can find proposed spec for vertex and fragment program debugging.
This model introduces callbacks to simplify IHV’s implementation. ISVs can in the callback query various GL state.

Sqrt’s solution is very handy I must say. One can imagine a debugger that in the first step redners one frame of animation and then allows user to select a particular vertex or pixel and execute it step-by-step. Although exporting all the possible combinations of render calls (DrawElements, DrawArrays, etc.) might not be such a good idea.

Maybe Im wrong, but I am thinking more about an API that allows you quickly add one call here and here and inspect your broken app. No need to replace existing render calls, just add some enable (glEnable (GL_SHADER_DEBUG)?), some query functions (for getting and setting intermediate values) and you are ready to go.

Im open for suggestions.

OK, just so you know where I am comming from, I develop GLIntercept and the debugger interface I had in mind was:

  • Let app run normally
  • User opens the run-time shader editor
  • If user adds a breakpoint(with a specific pixel/vertex number), break and create a Mesa offscreen surface and copy all relevant GL states.
  • Debug using mesa.
  • Any edits get compiled back into main app(as currently happens) and Mesa gets a new copy. (kinda like edit-and-continue debugging)
  • Let app continue

Using the suggestions in the above post, you don’t have to have a new render function(s) (you could use the existing ones and detect when in a ShaderDebugBegin/End statement - I just though it might be simplier to implement for you if there were only specific render calls)

I would also be happy with a glEnable/Disable GL_FRAGMENT/VERTEX_DEBUG switch instead of the Begin/End. (Which would do essentially the same thing. )

An addition to the above “spec” of mine. It would be nice to query if a line position is valid for the current debug . (ie. boolean IsShaderDebugLineValid(GLuint lineNum); as a lot of lines may not be valid to add a breakpoint to - whitespace/preprocessor stuff/ formatting etc )

Looking at that old spec, I could live with someting like it (as long as you added vertex/pixel location selection) but I do feel my design is a bit more GLish as it does not have callbacks. (Would callbacks be a problem in non-C languages?)

Also from the old spec, is changing values while debugging going to be out of the question?

But at the end of the day, you are implementing it (and it is not a core OpenGL feature) so as long as it is reliable, I should be happy.

sqrt suggestion is good because we need to be able to track vertices and fragments.

Adding glGetCurrentLine(char *thisline)
would be nice so that I can immediatly see the line.

For fragment debugging we can send GL_POINTS I suppose.

Has MESA_program_debug been implemented? How do people feel using it?

Originally posted by V-man:
[…]
Has MESA_program_debug been implemented? How do people feel using it?

Im affraid it wasnt fully implemented. This spec is not even listed on the mesa’s home page, it is hidden.

Brian enhanced NV programs with PRINT instruction which basicly allow you to spit diagnostic messages in conjunction with selected register.

I dont know why program_debug wasnt finished. Maybe it is because today you can buy gfx card for $50 and run programs smoothly (unlike software solutions). A developer, if he/she has a problem with a shader, just writes the intermediate results to fragment color and watches the screen.

Maybe todays shaders are so simple that they dont need debuggers yet. And that means it is a matter of time to feel the need for a debugger.

Michal,

I would have to respectfully disagree. Shaders are quickly getting more complicated, and a debugger would be a great help to today’s developers. Shaders are destined to get even more complicated as hardware improves, so this is definitely something that would be useful!

Ok, after rethinkig it, would it be acceptable to have the following functionality?

  1. No glEnable(GL_VERTEX/FRAGMENT_SHADER_DEBUG) nor glBeginShaderDebug - the debug mode is a particular program’s (or shader’s) state and it applies after linking (or compiling), so:
 glSetProgramDebugOption (GL_FRAGMENT_SHADER_DEBUG, GL_TRUE);
glLinkProgram (); 

The reason is to know whether the program is intended to run in software or hardware. If GL_TRUE for program/shader debugging was specified prior linking/compiling the code is translated against some virtual machine (not the real hardware) to be easily interpreted and debugged.

  1. No debug-specific draw calls, existing (i.e. glDrawElements()) are sufficent.

  2. Instead of glGetShaderDebugNextLine, as sqrt suggested, glStep are introduced. First invocation of this function would execute all the code for which vertex number/fragment window coordinate conditions are not met and would stop on the first executable statement of the main function. At this point you could query all the stuff you mentioned in the previous posts (current line number, current line text and variable values (+ modify them) to name a few). All consecutive calls to glStep would get you either to then next executable statement in current function or step you into (if possible) to other functions (this would be specified as a parameter to glStep). Executing the last statement would automatically execute all the code for remaining vertices and pixels. Maybe it would stop again if a given fragment is overdrawn?

#1 is ok with me but maybe debugging should be in a separate mesa implementation, unless sometime in the future there is going to be the ability to debug the hw (example : download temporary registers).

#2 was not needed at all

#3 glGetShaderDebugNextLine should work like that anyway, just like using a C++ debugger. Having functions like setting a breakpoint would be nice.
Step into, step over, run to next breakpoint.
Some people may have long shaders and they will get bored stepping line by line.

Originally posted by V-man:
#1 is ok with me but maybe debugging should be in a separate mesa implementation, unless sometime in the future there is going to be the ability to debug the hw (example : download temporary registers).
What do you mean by a separate mesa implementation?

#3 glGetShaderDebugNextLine should work like that anyway, just like using a C++ debugger. Having functions like setting a breakpoint would be nice.
Step into, step over, run to next breakpoint.
Some people may have long shaders and they will get bored stepping line by line.

Yes, breakpoint are essential part of the debugger. Also, some assert() function would be neat.

Getting back to #1, the rationale is to simplify the implementation. In the future mesa will have several “shader targets” - for example SSE target. There is also an interpreter to which mesa will fallback if the shader is too complex or the SSE is not present on the host processor. Knowing whether the shader is going to be debugged eliminates the need to recompile the shader to a different target. Since SSE is the prefered target, shaders are compiled against SSE. Explicitly specifying shader usage (debug it or not) will force interpreter to be used insted.
I ask because I dont see any problems that would arise if you were forced to specify debug option before compilation. If you see such a scenario, let me know and I will code the more general form (any shader is a subject to debugging and if it is not debugged at the moment, the faster path (like SSE) is used).

Thanks.

1, 2 and 3 are all fine with me.

I personally do not need what V-Man suggested (setting breakpoints, run to next break point, step into function etc) as that is easily implemented on my side of the code. (by continually calling glStep until a break point, and skipping functions etc…)

But I may need to know if a glStep call “stepped” in to a new function.

I would still like some way of knowing what the valid code lines in a shader are as well. (ie my IsShaderDebugLineValid(GLuint lineNum) above)

ild love to see verbose warning/error information about the shaders
with nvidia if u turn on strict compiler inforcement u get like 100 warnings/errors on a 40line shader, unfortunaly it doesnt offer much info what the exact problems are.
3dlabs glsl syntax validator aint the best either

Originally posted by _michal:
[QUOTE]What do you mean by a separate mesa implementation?
Sorry. I meant the same Mesa software code, but shader debugging ability added. Those debugging function are not going to be used when hw acceleration is used, right? So another source+binary can be distributed for this purpose alone.
In the D3D world, MS has created their normal d3d DLL and their reference rasterizer DLL.
For shader debugging, the reference rasterizer must be used.

Or maybe I’m just thinking differently…

PS: I have used D3D’s feature to compare results and found a bug in the driver. It’s nice to have something to compare with.

Originally posted by sqrt[-1]:
I personally do not need what V-Man suggested (setting breakpoints, run to next break point, step into function etc) as that is easily implemented on my side of the code. (by continually calling glStep until a break point, and skipping functions etc…)

Yes, it’s just a matter of terminology. Any functionality that can be done at the application side could be removed if it had not too much performance impact.

Originally posted by sqrt[-1]:

But I may need to know if a glStep call “stepped” in to a new function.

You could query the current stack context. Just like in modern debuggers.

Originally posted by zed:
ild love to see verbose warning/error information about the shaders
with nvidia if u turn on strict compiler inforcement u get like 100 warnings/errors on a 40line shader, unfortunaly it doesnt offer much info what the exact problems are.
3dlabs glsl syntax validator aint the best either

Could you tell us more about the 3dlabs’ syntax validator?
You see, we are planning to use the 3dlabs’ compiler (the syntax validator uses it), but because of time constraints and problems with porting it to mesa (it is written in a very unclean C++ way) I had to write from scratch my own compiler in C (it misses preprocessor and error reporting but accepts any well-formed code). When we get a running system, I am going to get back to the 3dlabs’ compiler an try to plug it in again.

How serious are the problems with 3dlabs’ validator? After inspecting the sources myself, I noticed that it performs constant folding and dead code elimination BEFORE the semantic pass. It means that the dead code is never checked.

How serious are the problems with 3dlabs’ validator? After inspecting the sources myself, I noticed that it performs constant folding and dead code elimination BEFORE the semantic pass. It means that the dead code is never checked.
Generally, what you say is not true. Could you email me an example? For example, the code

    if (false)
        3 + 2.4;
  

gets a semantic error for mixing ints and floats.

It is true that the grammar productions build the parse tree and do semantic checking at the same time, where other parsers might use separate passes. The presence of the defect you describe would be a corner case that should be fixed, if it exists.

I would agree that better error handling would be nice. The current error handling is pretty rudimentary.

JohnK

Originally posted by John Kessenich:
[b]Generally, what you say is not true. Could you email me an example? For example, the code

    if (false)
        3 + 2.4;
  

gets a semantic error for mixing ints and floats.
[/b]
Dont get me wrong, Im all for the 3dlabs’ compiler and it is going to be incorporated into mesa. And here is an example:

 
(true ? gl_FragColor.x : gl_FragColor.y) = 1.0; 

The code above is ill-formed, but is accepted. In the same time the code below:

 
(gl_FrontFacing ? gl_FragColor.x : gl_FragColor.y) = 1.0;
 

will not be accepted and this is a correct behaviour.

I made an attempt to port 3dlabs’ compiler in the beginning of 2005. There were so serious problems with compiling it (even on my machine) + the code was so horrible (with all the respect) + I have got a little time left, that I had to do it myself.
When this all stabilizes I’ll return to the origin al plan A.

The point is, there cant be a good debugger if the compiler itself is not reliable. While Im working on this I could also work on improving a little the 3dlabs’ part.