Example #1
0
ShaderGLES2::Version *ShaderGLES2::get_current_version() {

	Version *_v = version_map.getptr(conditional_version);

	if (_v) {
		if (conditional_version.code_version != 0) {
			CustomCode *cc = custom_code_map.getptr(conditional_version.code_version);
			ERR_FAIL_COND_V(!cc, _v);
			if (cc->version == _v->code_version)
				return _v;
		} else {
			return _v;
		}
	}

	if (!_v)
		version_map[conditional_version] = Version();

	Version &v = version_map[conditional_version];

	if (!_v) {
		v.uniform_location = memnew_arr(GLint, uniform_count);
	} else {
		if (v.ok) {
			glDeleteShader(v.vert_id);
			glDeleteShader(v.frag_id);
			glDeleteProgram(v.id);
			v.id = 0;
		}
	}

	v.ok = false;

	Vector<const char *> strings;

#ifdef GLES_OVER_GL
	strings.push_back("#version 120\n");
	strings.push_back("#define USE_GLES_OVER_GL\n");
#else
	strings.push_back("#version 100\n");
//angle does not like
#ifdef JAVASCRIPT_ENABLED
	strings.push_back("#define USE_HIGHP_PRECISION\n");
#endif

#endif

	int define_line_ofs = 1;

	for (int j = 0; j < conditional_count; j++) {
		bool enable = (conditional_version.version & (1 << j)) > 0;

		if (enable) {
			strings.push_back(conditional_defines[j]);
			define_line_ofs++;
			DEBUG_PRINT(conditional_defines[j]);
		}
	}

	// keep them around during the function
	CharString code_string;
	CharString code_string2;
	CharString code_globals;

	CustomCode *cc = NULL;

	if (conditional_version.code_version > 0) {
		cc = custom_code_map.getptr(conditional_version.code_version);

		ERR_FAIL_COND_V(!cc, NULL);
		v.code_version = cc->version;
		define_line_ofs += 2;
	}

	// program

	v.id = glCreateProgram();
	ERR_FAIL_COND_V(v.id == 0, NULL);

	if (cc) {
		for (int i = 0; i < cc->custom_defines.size(); i++) {
			strings.push_back(cc->custom_defines.write[i]);
			DEBUG_PRINT("CD #" + itos(i) + ": " + String(cc->custom_defines[i].get_data()));
		}
	}

	// vertex shader

	int string_base_size = strings.size();

	strings.push_back(vertex_code0.get_data());

	if (cc) {
		code_globals = cc->vertex_globals.ascii();
		strings.push_back(code_globals.get_data());
	}

	strings.push_back(vertex_code1.get_data());

	if (cc) {
		code_string = cc->vertex.ascii();
		strings.push_back(code_string.get_data());
	}

	strings.push_back(vertex_code2.get_data());

#ifdef DEBUG_SHADER

	DEBUG_PRINT("\nVertex Code:\n\n" + String(code_string.get_data()));

#endif

	v.vert_id = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(v.vert_id, strings.size(), &strings[0], NULL);
	glCompileShader(v.vert_id);

	GLint status;

	glGetShaderiv(v.vert_id, GL_COMPILE_STATUS, &status);
	if (status == GL_FALSE) {
		GLsizei iloglen;
		glGetShaderiv(v.vert_id, GL_INFO_LOG_LENGTH, &iloglen);

		if (iloglen < 0) {
			glDeleteShader(v.vert_id);
			glDeleteProgram(v.id);
			v.id = 0;

			ERR_PRINT("No OpenGL vertex shader compiler log. What the frick?");
		} else {
			if (iloglen == 0) {
				iloglen = 4096; // buggy driver (Adreno 220+)
			}

			char *ilogmem = (char *)Memory::alloc_static(iloglen + 1);
			ilogmem[iloglen] = '\0';
			glGetShaderInfoLog(v.vert_id, iloglen, &iloglen, ilogmem);

			String err_string = get_shader_name() + ": Vertex shader compilation failed:\n";

			err_string += ilogmem;

			_display_error_with_code(err_string, strings);

			Memory::free_static(ilogmem);
			glDeleteShader(v.vert_id);
			glDeleteProgram(v.id);
			v.id = 0;
		}

		ERR_FAIL_V(NULL);
	}

	strings.resize(string_base_size);

	// fragment shader

	strings.push_back(fragment_code0.get_data());

	if (cc) {
		code_globals = cc->fragment_globals.ascii();
		strings.push_back(code_globals.get_data());
	}

	strings.push_back(fragment_code1.get_data());

	if (cc) {
		code_string = cc->light.ascii();
		strings.push_back(code_string.get_data());
	}

	strings.push_back(fragment_code2.get_data());

	if (cc) {
		code_string2 = cc->fragment.ascii();
		strings.push_back(code_string2.get_data());
	}

	strings.push_back(fragment_code3.get_data());

#ifdef DEBUG_SHADER

	if (cc) {
		DEBUG_PRINT("\nFragment Code:\n\n" + String(cc->fragment_globals));
	}
	DEBUG_PRINT("\nFragment Code:\n\n" + String(code_string.get_data()));
#endif

	v.frag_id = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(v.frag_id, strings.size(), &strings[0], NULL);
	glCompileShader(v.frag_id);

	glGetShaderiv(v.frag_id, GL_COMPILE_STATUS, &status);
	if (status == GL_FALSE) {
		GLsizei iloglen;
		glGetShaderiv(v.frag_id, GL_INFO_LOG_LENGTH, &iloglen);

		if (iloglen < 0) {
			glDeleteShader(v.frag_id);
			glDeleteShader(v.vert_id);
			glDeleteProgram(v.id);
			v.id = 0;

			ERR_PRINT("No OpenGL fragment shader compiler log. What the frick?");
		} else {
			if (iloglen == 0) {
				iloglen = 4096; // buggy driver (Adreno 220+)
			}

			char *ilogmem = (char *)Memory::alloc_static(iloglen + 1);
			ilogmem[iloglen] = '\0';
			glGetShaderInfoLog(v.frag_id, iloglen, &iloglen, ilogmem);

			String err_string = get_shader_name() + ": Fragment shader compilation failed:\n";

			err_string += ilogmem;

			_display_error_with_code(err_string, strings);

			Memory::free_static(ilogmem);
			glDeleteShader(v.frag_id);
			glDeleteShader(v.vert_id);
			glDeleteProgram(v.id);
			v.id = 0;
		}

		ERR_FAIL_V(NULL);
	}

	glAttachShader(v.id, v.frag_id);
	glAttachShader(v.id, v.vert_id);

	// bind the attribute locations. This has to be done before linking so that the
	// linker doesn't assign some random indices

	for (int i = 0; i < attribute_pair_count; i++) {
		glBindAttribLocation(v.id, attribute_pairs[i].index, attribute_pairs[i].name);
	}

	glLinkProgram(v.id);

	glGetProgramiv(v.id, GL_LINK_STATUS, &status);
	if (status == GL_FALSE) {
		GLsizei iloglen;
		glGetProgramiv(v.id, GL_INFO_LOG_LENGTH, &iloglen);

		if (iloglen < 0) {
			glDeleteShader(v.frag_id);
			glDeleteShader(v.vert_id);
			glDeleteProgram(v.id);
			v.id = 0;

			ERR_PRINT("No OpenGL program link log. What the frick?");
			ERR_FAIL_V(NULL);
		}

		if (iloglen == 0) {
			iloglen = 4096; // buggy driver (Adreno 220+)
		}

		char *ilogmem = (char *)Memory::alloc_static(iloglen + 1);
		ilogmem[iloglen] = '\0';
		glGetProgramInfoLog(v.id, iloglen, &iloglen, ilogmem);

		String err_string = get_shader_name() + ": Program linking failed:\n";

		err_string += ilogmem;

		_display_error_with_code(err_string, strings);

		Memory::free_static(ilogmem);
		glDeleteShader(v.frag_id);
		glDeleteShader(v.vert_id);
		glDeleteProgram(v.id);
		v.id = 0;

		ERR_FAIL_V(NULL);
	}

	// get uniform locations

	glUseProgram(v.id);

	for (int i = 0; i < uniform_count; i++) {
		v.uniform_location[i] = glGetUniformLocation(v.id, uniform_names[i]);
	}

	for (int i = 0; i < texunit_pair_count; i++) {
		GLint loc = glGetUniformLocation(v.id, texunit_pairs[i].name);
		if (loc >= 0) {
			if (texunit_pairs[i].index < 0) {
				glUniform1i(loc, max_image_units + texunit_pairs[i].index);
			} else {
				glUniform1i(loc, texunit_pairs[i].index);
			}
		}
	}

	if (cc) {
		// uniforms
		for (int i = 0; i < cc->custom_uniforms.size(); i++) {
			String native_uniform_name = _mkid(cc->custom_uniforms[i]);
			GLint location = glGetUniformLocation(v.id, (native_uniform_name).ascii().get_data());
			v.custom_uniform_locations[cc->custom_uniforms[i]] = location;
		}

		// textures
		for (int i = 0; i < cc->texture_uniforms.size(); i++) {
			String native_uniform_name = _mkid(cc->texture_uniforms[i]);
			GLint location = glGetUniformLocation(v.id, (native_uniform_name).ascii().get_data());
			v.custom_uniform_locations[cc->texture_uniforms[i]] = location;
		}
	}

	glUseProgram(0);
	v.ok = true;

	if (cc) {
		cc->versions.insert(conditional_version.version);
	}

	return &v;
}
Example #2
0
ShaderGLES3::Version *ShaderGLES3::get_current_version() {

	Version *_v = version_map.getptr(conditional_version);

	if (_v) {

		if (conditional_version.code_version != 0) {
			CustomCode *cc = custom_code_map.getptr(conditional_version.code_version);
			ERR_FAIL_COND_V(!cc, _v);
			if (cc->version == _v->code_version)
				return _v;
		} else {
			return _v;
		}
	}

	if (!_v)
		version_map[conditional_version] = Version();

	Version &v = version_map[conditional_version];

	if (!_v) {

		v.uniform_location = memnew_arr(GLint, uniform_count);

	} else {
		if (v.ok) {
			//bye bye shaders
			glDeleteShader(v.vert_id);
			glDeleteShader(v.frag_id);
			glDeleteProgram(v.id);
			v.id = 0;
		}
	}

	v.ok = false;
	/* SETUP CONDITIONALS */

	Vector<const char *> strings;
#ifdef GLES_OVER_GL
	strings.push_back("#version 330\n");
	strings.push_back("#define GLES_OVER_GL\n");
#else
	strings.push_back("#version 300 es\n");
#endif

	int define_line_ofs = 1;

	for (int i = 0; i < custom_defines.size(); i++) {

		strings.push_back(custom_defines[i].get_data());
		define_line_ofs++;
	}

	for (int j = 0; j < conditional_count; j++) {

		bool enable = ((1 << j) & conditional_version.version);
		strings.push_back(enable ? conditional_defines[j] : "");
		if (enable)
			define_line_ofs++;

		if (enable) {
			DEBUG_PRINT(conditional_defines[j]);
		}
	}

	//keep them around during the function
	CharString code_string;
	CharString code_string2;
	CharString code_globals;
	CharString material_string;

	CustomCode *cc = NULL;

	if (conditional_version.code_version > 0) {
		//do custom code related stuff

		ERR_FAIL_COND_V(!custom_code_map.has(conditional_version.code_version), NULL);
		cc = &custom_code_map[conditional_version.code_version];
		v.code_version = cc->version;
		define_line_ofs += 2;
	}

	/* CREATE PROGRAM */

	v.id = glCreateProgram();

	ERR_FAIL_COND_V(v.id == 0, NULL);

	/* VERTEX SHADER */

	if (cc) {
		for (int i = 0; i < cc->custom_defines.size(); i++) {

			strings.push_back(cc->custom_defines[i].get_data());
			DEBUG_PRINT("CD #" + itos(i) + ": " + String(cc->custom_defines[i]));
		}
	}

	int strings_base_size = strings.size();

	//vertex precision is high
	strings.push_back("precision highp float;\n");
	strings.push_back("precision highp int;\n");
#ifndef GLES_OVER_GL
	strings.push_back("precision highp sampler2D;\n");
	strings.push_back("precision highp samplerCube;\n");
	strings.push_back("precision highp sampler2DArray;\n");
#endif

	strings.push_back(vertex_code0.get_data());

	if (cc) {
		material_string = cc->uniforms.ascii();
		strings.push_back(material_string.get_data());
	}

	strings.push_back(vertex_code1.get_data());

	if (cc) {
		code_globals = cc->vertex_globals.ascii();
		strings.push_back(code_globals.get_data());
	}

	strings.push_back(vertex_code2.get_data());

	if (cc) {
		code_string = cc->vertex.ascii();
		strings.push_back(code_string.get_data());
	}

	strings.push_back(vertex_code3.get_data());
#ifdef DEBUG_SHADER

	DEBUG_PRINT("\nVertex Code:\n\n" + String(code_string.get_data()));
	for (int i = 0; i < strings.size(); i++) {

		//print_line("vert strings "+itos(i)+":"+String(strings[i]));
	}
#endif

	v.vert_id = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(v.vert_id, strings.size(), &strings[0], NULL);
	glCompileShader(v.vert_id);

	GLint status;

	glGetShaderiv(v.vert_id, GL_COMPILE_STATUS, &status);
	if (status == GL_FALSE) {
		// error compiling
		GLsizei iloglen;
		glGetShaderiv(v.vert_id, GL_INFO_LOG_LENGTH, &iloglen);

		if (iloglen < 0) {

			glDeleteShader(v.vert_id);
			glDeleteProgram(v.id);
			v.id = 0;

			ERR_PRINT("Vertex shader compilation failed with empty log");
		} else {

			if (iloglen == 0) {

				iloglen = 4096; //buggy driver (Adreno 220+....)
			}

			char *ilogmem = (char *)memalloc(iloglen + 1);
			ilogmem[iloglen] = 0;
			glGetShaderInfoLog(v.vert_id, iloglen, &iloglen, ilogmem);

			String err_string = get_shader_name() + ": Vertex Program Compilation Failed:\n";

			err_string += ilogmem;
			_display_error_with_code(err_string, strings);
			memfree(ilogmem);
			glDeleteShader(v.vert_id);
			glDeleteProgram(v.id);
			v.id = 0;
		}

		ERR_FAIL_V(NULL);
	}

	//_display_error_with_code("pepo", strings);

	/* FRAGMENT SHADER */

	strings.resize(strings_base_size);
	//fragment precision is medium
	strings.push_back("precision highp float;\n");
	strings.push_back("precision highp int;\n");
#ifndef GLES_OVER_GL
	strings.push_back("precision highp sampler2D;\n");
	strings.push_back("precision highp samplerCube;\n");
	strings.push_back("precision highp sampler2DArray;\n");
#endif

	strings.push_back(fragment_code0.get_data());
	if (cc) {
		material_string = cc->uniforms.ascii();
		strings.push_back(material_string.get_data());
	}

	strings.push_back(fragment_code1.get_data());

	if (cc) {
		code_globals = cc->fragment_globals.ascii();
		strings.push_back(code_globals.get_data());
	}

	strings.push_back(fragment_code2.get_data());

	if (cc) {
		code_string = cc->light.ascii();
		strings.push_back(code_string.get_data());
	}

	strings.push_back(fragment_code3.get_data());

	if (cc) {
		code_string2 = cc->fragment.ascii();
		strings.push_back(code_string2.get_data());
	}

	strings.push_back(fragment_code4.get_data());

#ifdef DEBUG_SHADER
	DEBUG_PRINT("\nFragment Globals:\n\n" + String(code_globals.get_data()));
	DEBUG_PRINT("\nFragment Code:\n\n" + String(code_string2.get_data()));
	for (int i = 0; i < strings.size(); i++) {

		//print_line("frag strings "+itos(i)+":"+String(strings[i]));
	}
#endif

	v.frag_id = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(v.frag_id, strings.size(), &strings[0], NULL);
	glCompileShader(v.frag_id);

	glGetShaderiv(v.frag_id, GL_COMPILE_STATUS, &status);
	if (status == GL_FALSE) {
		// error compiling
		GLsizei iloglen;
		glGetShaderiv(v.frag_id, GL_INFO_LOG_LENGTH, &iloglen);

		if (iloglen < 0) {

			glDeleteShader(v.frag_id);
			glDeleteShader(v.vert_id);
			glDeleteProgram(v.id);
			v.id = 0;
			ERR_PRINT("Fragment shader compilation failed with empty log");
		} else {

			if (iloglen == 0) {

				iloglen = 4096; //buggy driver (Adreno 220+....)
			}

			char *ilogmem = (char *)memalloc(iloglen + 1);
			ilogmem[iloglen] = 0;
			glGetShaderInfoLog(v.frag_id, iloglen, &iloglen, ilogmem);

			String err_string = get_shader_name() + ": Fragment Program Compilation Failed:\n";

			err_string += ilogmem;
			_display_error_with_code(err_string, strings);
			ERR_PRINT(err_string.ascii().get_data());
			memfree(ilogmem);
			glDeleteShader(v.frag_id);
			glDeleteShader(v.vert_id);
			glDeleteProgram(v.id);
			v.id = 0;
		}

		ERR_FAIL_V(NULL);
	}

	glAttachShader(v.id, v.frag_id);
	glAttachShader(v.id, v.vert_id);

	// bind attributes before linking
	for (int i = 0; i < attribute_pair_count; i++) {

		glBindAttribLocation(v.id, attribute_pairs[i].index, attribute_pairs[i].name);
	}

	//if feedback exists, set it up

	if (feedback_count) {
		Vector<const char *> feedback;
		for (int i = 0; i < feedback_count; i++) {

			if (feedbacks[i].conditional == -1 || (1 << feedbacks[i].conditional) & conditional_version.version) {
				//conditional for this feedback is enabled
				feedback.push_back(feedbacks[i].name);
			}
		}

		if (feedback.size()) {
			glTransformFeedbackVaryings(v.id, feedback.size(), feedback.ptr(), GL_INTERLEAVED_ATTRIBS);
		}
	}

	glLinkProgram(v.id);

	glGetProgramiv(v.id, GL_LINK_STATUS, &status);

	if (status == GL_FALSE) {
		// error linking
		GLsizei iloglen;
		glGetProgramiv(v.id, GL_INFO_LOG_LENGTH, &iloglen);

		if (iloglen < 0) {

			glDeleteShader(v.frag_id);
			glDeleteShader(v.vert_id);
			glDeleteProgram(v.id);
			v.id = 0;
			ERR_FAIL_COND_V(iloglen <= 0, NULL);
		}

		if (iloglen == 0) {

			iloglen = 4096; //buggy driver (Adreno 220+....)
		}

		char *ilogmem = (char *)Memory::alloc_static(iloglen + 1);
		ilogmem[iloglen] = 0;
		glGetProgramInfoLog(v.id, iloglen, &iloglen, ilogmem);

		String err_string = get_shader_name() + ": Program LINK FAILED:\n";

		err_string += ilogmem;
		_display_error_with_code(err_string, strings);
		ERR_PRINT(err_string.ascii().get_data());
		Memory::free_static(ilogmem);
		glDeleteShader(v.frag_id);
		glDeleteShader(v.vert_id);
		glDeleteProgram(v.id);
		v.id = 0;

		ERR_FAIL_V(NULL);
	}

	/* UNIFORMS */

	glUseProgram(v.id);

	//print_line("uniforms:  ");
	for (int j = 0; j < uniform_count; j++) {

		v.uniform_location[j] = glGetUniformLocation(v.id, uniform_names[j]);
		//print_line("uniform "+String(uniform_names[j])+" location "+itos(v.uniform_location[j]));
	}

	// set texture uniforms
	for (int i = 0; i < texunit_pair_count; i++) {

		GLint loc = glGetUniformLocation(v.id, texunit_pairs[i].name);
		if (loc >= 0) {
			if (texunit_pairs[i].index < 0) {
				glUniform1i(loc, max_image_units + texunit_pairs[i].index); //negative, goes down
			} else {

				glUniform1i(loc, texunit_pairs[i].index);
			}
		}
	}

	// assign uniform block bind points
	for (int i = 0; i < ubo_count; i++) {

		GLint loc = glGetUniformBlockIndex(v.id, ubo_pairs[i].name);
		if (loc >= 0)
			glUniformBlockBinding(v.id, loc, ubo_pairs[i].index);
	}

	if (cc) {

		v.texture_uniform_locations.resize(cc->texture_uniforms.size());
		for (int i = 0; i < cc->texture_uniforms.size(); i++) {

			v.texture_uniform_locations.write[i] = glGetUniformLocation(v.id, String(cc->texture_uniforms[i]).ascii().get_data());
			glUniform1i(v.texture_uniform_locations[i], i + base_material_tex_index);
		}
	}

	glUseProgram(0);

	v.ok = true;

	return &v;
}