recompile the shader on runtime, like hot plug the new compiled shader

I am spending too much time running the render engine when i do a small change on mu GLSL shaders.

I have implemented a method that runs on a separate thread and checks for shader file stamps to see if they are different. If they are then i recompile the shaders. I plan to do this in future with OS calls and remove this not very efficient method.

I have e problem however that i can not create the program. I get invalid error for some reasons and i dont know how to fix it the whole day. :S

I also noted that i get 0 when i want to create a shader even if the shader doesn’t have errors.
Also do i need to set uniforms again ??

Thanks guys for help :smiley:



GLuint ShaderProgram::createProgram(){

	GLuint newProgramId = glCreateProgram();
	if (newProgramId == 0){
		log_.error(std::string("Failed to create new program: "));
		
		checkForError(programName_.c_str(), "createProgram");
		for (auto& i : shaders_){
			glDetachShader(newProgramId, i.second.getId());
		}
		return 0;
	}

	deleteProgram();
	for (auto& i : shaders_){
		glAttachShader(newProgramId, i.second.getId());
	}

	glLinkProgram(newProgramId);

	GLint shaderStatus;
	glGetProgramiv(newProgramId, GL_LINK_STATUS, &shaderStatus);
	if (shaderStatus == GL_FALSE){

		GLint infoLogLength;
		glGetProgramiv(newProgramId, GL_INFO_LOG_LENGTH, &infoLogLength);

		GLchar *strInfoLog = new GLchar[infoLogLength + 1];
		glGetProgramInfoLog(newProgramId, infoLogLength, NULL, strInfoLog);
		//fprintf(stderr, "Linker failure: %s
", strInfoLog);
		log_.error(std::string("Linker failure: ") + programName_ + ", " + strInfoLog + " program Id: " + std::to_string(newProgramId));

		delete[] strInfoLog;
		return -1;
	}

	checkForError(programName_.c_str(), "createProgram");

	deleteProgram();
	for (auto& i : shaders_){
		glDetachShader(newProgramId, i.second.getId());
		glDeleteShader(i.second.getId());
	}

	
	log_.info(std::string("New shader program created: ") + programName_ + " with ID " + std::to_string(newProgramId));
	programId_ = newProgramId;

	if (!isModifiedThread_)
		isModifiedThread_ = new std::thread(&ShaderProgram::checkForModifyed, this, timer);
	//isModifiedThread_->join();
	return programId_;
}

void ShaderProgram::checkForModifyed(int timer){

	while (true){ // use mutex to break the stop the loop and finish thread exceuton to release resourses on program close
		std::this_thread::sleep_for(std::chrono::seconds(timer));

		for (auto& i : shaders_){
			if (i.second.isModified()){
				log_.debug(std::string("Shader modified: ") + i.second.getPath());
				//for (auto& j : shaders_){
				//	createShader(j.second.getType(), j.second.getPath());
				//}
				createShader(i.second.getType(), i.second.getPath());
				//deleteProgram();
				createProgram();
				//shaders_.erase(i);
			}
		}
	}	
}


void ShaderProgram::startThread() {
	//mutex.lock();
	//thread.start(threadMethod);
}

void ShaderProgram::stopThread() {
	//mutex.unlock();
	//thread.join();
}

Are you trying to compile the shaders in a different thread? If so, does that thread have a context bound to it? Does the context share data with the context used by the rendering thread?

I do poll in a different thread for file chances so i guess there is no data shared. I forgot about that. I will check and post what I did

As for now my whole render engine is on one thread will i decide to implement culling before sending the draw command. This will be done probablly after i fix a bug with spot light, work on shadows a bit more, and use some more C++11

This is how i create the thread

 
isModifiedThread_ = new std::thread(&ShaderProgram::checkForModifyed, this, timer);

UPDATE: they do share all the data and i still get that Invalid operation :S. still looking to fix it but i have no clue now what is happening.
and this should share the data. I will write some code inside that thread instead of calling methods to compile shaders and see that will happen.

I have to go at training now but here is the link to github code https://github.com/lumx/GameEngine/blob/master/GameEngine/src/Core/Render/ShaderProgram.cpp. In mean time i will think for a solution but still it does not seem very obvious to me. Like usual the problem is in front on my eyes but i just cant see it :S

UPDATE2: Ok i guess i know what it is but i dont know how to fix it. When i pass the values to the thread those are copied and things get screwed up because i dont have a context bound. While looking at values in debugger i got tricked because the values were the same and i though i am referring to the same class and im not copying it but is seems that i do.

Now my problem is how to fix this syntactically in C++. I have no idea now. I treid also this but it is not working

 isModifiedThread_ = new std::thread(ShaderProgram::checkForModifyed, std::ref(*this), timer); 

and this one does not even compile

 isModifiedThread_ = new std::thread(std::ref(&this->checkForModifyed), std::ref(*this), timer);