Error while updating shader uniforms - "Access violation reading location"

Hi,

I’ve recently migrated to Cocos 3.3 from 2.2.5 and am unable to make shader work stable. Sometimes, not very often and quite randomly (I’m unable to figure when) game crashes in std::unordered_map::find while updating uniforms. Here’s an example of call stack:

  • libcocos2d.dll!std::equal_to::operator()(const int & _Left, const int & _Right) Line 169    C++
  • libcocos2d.dll!std::_Uhash_compare<int,std::hash,std::equal_to >::operator()(const int & _Keyval1, const int & _Keyval2) Line 253    C++
  • libcocos2d.dll!std::_Hash<std::_Umap_traits<int,cocos2d::UniformValue,std::_Uhash_compare<int,std::hash,std::equal_to >,std::allocator<std::pair<int const ,cocos2d::UniformValue> >,0> >::lower_bound(const int & _Keyval) Line 749    C++
  • libcocos2d.dll!std::_Hash<std::_Umap_traits<int,cocos2d::UniformValue,std::_Uhash_compare<int,std::hash,std::equal_to >,std::allocator<std::pair<int const ,cocos2d::UniformValue> >,0> >::find(const int & _Keyval) Line 728    C++
  • libcocos2d.dll!cocos2d::GLProgramState::getUniformValue(int uniformLocation) Line 398    C++
  • libcocos2d.dll!cocos2d::GLProgramState::setUniformVec4(int uniformLocation, const cocos2d::Vec4 & value) Line 551    C++
  • Game.exe!TintSprite::updateShaderUniforms() Line 121    C++
  • Game.exe!TintSprite::draw(cocos2d::Renderer * renderer, const cocos2d::Mat4 & transform, unsigned int flags) Line 100    C++
  • libcocos2d.dll!cocos2d::Node::visit(cocos2d::Renderer * renderer, const cocos2d::Mat4 & parentTransform, unsigned int parentFlags) Line 1297    C++

I’m using simple fragment shader to tint sprites:

#ifdef GL_ES
precision mediump float;
#endif

varying vec4 v_fragmentColor;
varying vec2 v_texCoord;

uniform vec4 add;
uniform vec4 multy;

void main() {
    vec4 current = texture2D(CC_Texture0, v_texCoord);
    gl_FragColor = (current * multy + add * current.a) * multy.a;
}

First, I create a shader instance:

auto fileUtiles = FileUtils::getInstance();
auto fragmentFullPath = fileUtiles->fullPathForFilename("assets/shaders/tint.fsh");
auto fragSource = fileUtiles->getStringFromFile(fragmentFullPath);
auto glprogram = GLProgram::createWithByteArrays(ccPositionTextureColor_noMVP_vert, fragSource.c_str());
glprogram->retain();

addLocation = glprogram->getUniformLocation("add"); //static variable
multyLocation = glprogram->getUniformLocation("multy"); //static variable

tintShader = glprogram; //static variable

I apply it to sprites in such way:

setGLProgramState(GLProgramState::create(tintShader));

Sprite’s draw with uniforms updating:

void TintSprite::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
{
    multy.w = getDisplayedOpacity() / 255.f;
    updateShaderUniforms();

    Sprite::draw(renderer, transform, flags);
}

void TintSprite::updateShaderUniforms()
{
    getGLProgramState()->setUniformVec4(addLocation, add);
    getGLProgramState()->setUniformVec4(multyLocation, multy);
}

According to debug information, uniform location is ‘3’ and this really key exists in ‘_uniforms’ map, but ‘find’ method still crashes somwhere inside std while trying to get value from map by this key.

Could you please suggest in which direction shall I move in order to fix this issue?

Thanks

It seems there is more correct way how to use shaders - add GLProgram into cache, then obtain GLProgramState from cache and update uniforms in custom renderer command before drawing sprite. Hope the shader will work more stable with this approach