Bug: copyMatchingNamedConstantsFrom(...) autoparam overwrite

Anything and everything that's related to OGRE or the wider graphics field that doesn't fit into the other forums.
Post Reply
Ident
Gremlin
Posts: 155
Joined: Thu Sep 17, 2009 8:43 pm
Location: Austria
x 9
Contact:

Bug: copyMatchingNamedConstantsFrom(...) autoparam overwrite

Post by Ident »

I am using Ogre default branch REV 6327:

I change my fragment program of a material dynamically in run-time. For this i access the pass and set it:

Code: Select all

currentPass->setFragmentProgram(fragShaderName);
This works fine except for that on the next update a non-existant auto param is attempted to be updated resulting in a memory access violation.

On line 3502 in "OgreGpuProgramParams.cpp" the auto param gets changed.
At that point the iterator "mi" points to the value

Code: Select all

(0, "diffuseTexture")
which is correct i assume, as my material has defined this as a "param_named" parameter in the material file.
The other "fragment_program" i had previously set contains the following as first parameter:

Code: Select all

param_named_auto lightPosArray			light_position_view_space_array				2
While still in the debugging step i described above, i looked at "autoEntry.fData" which obviously points to an undefined value.Yet it is accepted as "true" and the "setNamedAutoConstantReal(...)" function is called. The autoEntry.paramType is equivalent to the one later causing the memory access violation.

I assume this is a bug. Maybe I did something wrong but i wouldn't know what. Took me some hours to figure out where the auto param is changed in this way.


Looking at the functions i especially do not understand the reasoning behind

Code: Select all

if (autoEntry.fData)
What is the logic behind overwriting parameters of different type in a function called "copyMatchingNamedConstantsFrom" - they aren't matcvhing still being overwritten.
Ident
Gremlin
Posts: 155
Joined: Thu Sep 17, 2009 8:43 pm
Location: Austria
x 9
Contact:

Re: Bug: copyMatchingNamedConstantsFrom(...) autoparam overw

Post by Ident »

This is how i temporarily fixed the occurance of the MAV:

Before i set my fragment program i call

Code: Select all

 currentPass->getFragmentProgramParameters().get()->clearAutoConstants();
User avatar
masterfalcon
OGRE Team Member
OGRE Team Member
Posts: 4270
Joined: Sun Feb 25, 2007 4:56 am
Location: Bloomington, MN
x 126
Contact:

Re: Bug: copyMatchingNamedConstantsFrom(...) autoparam overw

Post by masterfalcon »

Would you be able to provide some sample code, material and shader to reproduce this?
Ident
Gremlin
Posts: 155
Joined: Thu Sep 17, 2009 8:43 pm
Location: Austria
x 9
Contact:

Re: Bug: copyMatchingNamedConstantsFrom(...) autoparam overw

Post by Ident »

Sure. JFYI, I edited this post numerous times, so be sure you started reading after my last edit.

I want to say that the above workaround DOES NOT work and should not be used. I got a better functioning workaround which I will present at the end of my post.

This is an example of a base material, of which I use dozens, each one for a different object due to different textures, basically it is just empty and contains a different texture unit for each material which is the only thing that distinguishes them:

Code: Select all

material ExampleMaterial
{
    technique 0
    {
        pass 0
  		{
            texture_unit diffuseTexture 
            {
				texture whatever.jpg		
            }
        }
	}
}
These are two Ogre vertex shader programs i use:

Code: Select all

vertex_program regularTransform_vert glsl            
{
    source regularTransform.vert      
    entry_point main
    syntax glsl400
    
    default_params
    {
        param_named_auto worldViewProjMatrix    worldviewproj_matrix
        param_named_auto worldViewMatrix        worldview_matrix
    }
}


vertex_program stereoPlanar_vert glsl            
{
    source stereoPlanar.vert     
    entry_point main    
    syntax glsl400
    
    default_params
    {
		param_named_auto worldViewMatrix		worldview_matrix
		param_named_auto projectionMatrix		projection_matrix
		
		shared_params_ref SharedStereoParams
    }
}
The referenced shared parameters work absolutely fine in every case and I have had a great experience with them. I will not detail them any further because they are not the source of any troubles. Also the vertex shader matrices do work fine after the switch. Now let's get to the fragment shaders:

Code: Select all

// Fragment shader with light-based shading
fragment_program regularLighting_frag glsl            
{
    source regularLighting.frag
    entry_point main
    syntax glsl400
    
    default_params
    {
        param_named diffuseTexture int 0
        
        param_named_auto lightPosArray            light_position_view_space_array                2
        param_named_auto lightDirArray            light_direction_view_space_array               2
        param_named_auto lightAttenuationArray    light_attenuation_array                        2
        param_named_auto spotlightParamsArray     spotlight_params_array                         2
        param_named_auto lightDiffColourArray     light_diffuse_colour_power_scaled_array        2
    
        param_named_auto fogColour        fog_colour
        param_named_auto fogParams        fog_params
        
        param_named_auto ambientColour    ambient_light_colour
    }
}

// Fragment shader that only provides texturing
fragment_program regularTexturingOnly_frag glsl
{
    source regularTexturingOnly.frag
    entry_point main
    syntax glsl400
    
    default_params
    {
        param_named diffuseTexture int 0
    }
}
All these shaders work fine under normal circumstances and have the correctly named associated parameters inside the actual glsl shader programs, which are not reduced away by the compiler (otherwise a warning pops up anyways). This all runs without warnings and errors according to the Ogre log, under normal circumstances. I get a warning only if I attach the texturing frag shader to a vert shader with outputs that are not used as inputs in the frag shader, which is totally fine for my use-case and doesn't show as a problem during rendering.

Here is the code associated with switching the vertex/frag shaders:
I get the material, access the pass and then do the following:

Code: Select all

currentPass->setVertexProgram(vertShaderName);
currentPass->setFragmentProgram(fragShaderName);
To reconstruct my problem:
I first set "stereoPlanar_vert" and "regularLighting_frag" for the materials of two or more objects (I think one is enough though), and then switch to "stereoPlanar_vert" and "regularTexturingOnly_frag" for them in a next step. This will in the process of changing the shader remove the diffuseTexture (or whatever has physicalIndex 0 in both cases) param (or any other param depending on order) and replace it by copying the auto param from the old fragment shader which in that case was the lightPosArray with a totally different type. This effectively left the program with only one parameter namely the lightPosArray one and nothing else. Subsequently in the next renderStep the param is attempted to be updated resulting in an assert error, because obviously this can't work out.


I can't give you the glsl shader code because it is part of a research project, but there is nothing special about the shader programs themselves anyways and their content is irrelevant here, the only point is that the parameters have to be there and not be removed by the compiler.

In the following i copied my pretty much functional workaround for the issue. It work for almost all shader switches. When switching to the simpler fragment shader, only the vertex shader that was used at the point of switch will work together with thate fragment shader. The lighting frag shader works in any case in my project. The vertex shaders combined with the simpler fragment shader result in an oval white circle that covers the screen (Except for the one that was activated at the point of the switch). I have no idea how this happens or what this could mean.

First i retrieve the default params of the specific shader i want to switch to and get them as const so I can be sure I don't change them in any way ever (Possible shader names would be "stereoPlanar_vert" and "regularLighting_frag" in my example):

Code: Select all

  
GpuProgramPtr fragShader = Ogre::GpuProgramManager::getSingleton().getByName(fragShaderName);
GpuProgramPtr vertShader = Ogre::GpuProgramManager::getSingleton().getByName(vertShaderName);

const Ogre::GpuProgramParametersSharedPtr fragShadParams = fragShader.getPointer()->getDefaultParameters();
const Ogre::GpuProgramParametersSharedPtr vertShadParams = vertShader.getPointer()->getDefaultParameters();
After that i change the programs for all the materials i want to change, by retrieving pass 0 of technique 0 and then modifying it:

Code: Select all

        currentPass->setVertexProgram(vertShaderName, true);
        currentPass->setFragmentProgram(fragShaderName, true);

        currentPass->getFragmentProgramParameters().getPointer()->clearAutoConstants();
        currentPass->getVertexProgramParameters().getPointer()->clearAutoConstants();

        currentPass->getFragmentProgramParameters().getPointer()->copyConstantsFrom(*fragShadParams.getPointer());
        currentPass->getVertexProgramParameters().getPointer()->copyConstantsFrom(*vertShadParams.getPointer());
It took me a long time to figure out what works well for me, this is the only valid solution I got. It doesn't result in "crashes"/errors in any case. I also tried to modify the Ogre source code but this part of Ogre is written in a way that I have a very hard time reading the code without spending a lot more time on it which i just do not have anymore. The functions where the auto parameter copying occurs is immensely long and it is not clear what is happening and why, especially at the significant part that messes up the auto parameters, so I gave up on that, otherwise I would have provided a patch if I got it working anyhow but whatever I tried messed up something else in the end.
Post Reply