Ejemplo n.º 1
0
GPUShader *GPU_shader_create_ex(const char *vertexcode,
                                const char *fragcode,
                                const char *geocode,
                                const char *libcode,
                                const char *defines,
                                int input,
                                int output,
                                int number,
                                const int flags)
{
#ifdef WITH_OPENSUBDIV
	/* TODO(sergey): used to add #version 150 to the geometry shader.
	 * Could safely be renamed to "use_geometry_code" since it's very
	 * likely any of geometry code will want to use GLSL 1.5.
	 */
	bool use_opensubdiv = (flags & GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV) != 0;
#else
	UNUSED_VARS(flags);
	bool use_opensubdiv = false;
#endif
	GLint status;
	GLchar log[5000];
	GLsizei length = 0;
	GPUShader *shader;
	char standard_defines[MAX_DEFINE_LENGTH] = "";
	char standard_extensions[MAX_EXT_DEFINE_LENGTH] = "";

	if (geocode && !GPU_geometry_shader_support())
		return NULL;

	shader = MEM_callocN(sizeof(GPUShader), "GPUShader");
	gpu_dump_shaders(NULL, 0, DEBUG_SHADER_NONE);

	if (vertexcode)
		shader->vertex = glCreateShader(GL_VERTEX_SHADER);
	if (fragcode)
		shader->fragment = glCreateShader(GL_FRAGMENT_SHADER);
	if (geocode)
		shader->geometry = glCreateShader(GL_GEOMETRY_SHADER_EXT);

	shader->program = glCreateProgram();

	if (!shader->program ||
	    (vertexcode && !shader->vertex) ||
	    (fragcode && !shader->fragment) ||
	    (geocode && !shader->geometry))
	{
		fprintf(stderr, "GPUShader, object creation failed.\n");
		GPU_shader_free(shader);
		return NULL;
	}

	gpu_shader_standard_defines(standard_defines,
	                            use_opensubdiv,
	                            (flags & GPU_SHADER_FLAGS_NEW_SHADING) != 0);
	gpu_shader_standard_extensions(standard_extensions, geocode != NULL);

	if (vertexcode) {
		const char *source[5];
		/* custom limit, may be too small, beware */
		int num_source = 0;

		source[num_source++] = gpu_shader_version();
		source[num_source++] = standard_extensions;
		source[num_source++] = standard_defines;

		if (defines) source[num_source++] = defines;
		source[num_source++] = vertexcode;

		gpu_dump_shaders(source, num_source, DEBUG_SHADER_VERTEX);

		glAttachShader(shader->program, shader->vertex);
		glShaderSource(shader->vertex, num_source, source, NULL);

		glCompileShader(shader->vertex);
		glGetShaderiv(shader->vertex, GL_COMPILE_STATUS, &status);

		if (!status) {
			glGetShaderInfoLog(shader->vertex, sizeof(log), &length, log);
			shader_print_errors("compile", log, source, num_source);

			GPU_shader_free(shader);
			return NULL;
		}
	}

	if (fragcode) {
		const char *source[7];
		int num_source = 0;

		source[num_source++] = gpu_shader_version();
		source[num_source++] = standard_extensions;
		source[num_source++] = standard_defines;

#ifdef WITH_OPENSUBDIV
		/* TODO(sergey): Move to fragment shader source code generation. */
		if (use_opensubdiv) {
			source[num_source++] =
			        "#ifdef USE_OPENSUBDIV\n"
			        "in block {\n"
			        "	VertexData v;\n"
			        "} inpt;\n"
			        "#endif\n";
		}
#endif

		if (defines) source[num_source++] = defines;
		if (libcode) source[num_source++] = libcode;
		source[num_source++] = fragcode;

		gpu_dump_shaders(source, num_source, DEBUG_SHADER_FRAGMENT);

		glAttachShader(shader->program, shader->fragment);
		glShaderSource(shader->fragment, num_source, source, NULL);

		glCompileShader(shader->fragment);
		glGetShaderiv(shader->fragment, GL_COMPILE_STATUS, &status);

		if (!status) {
			glGetShaderInfoLog(shader->fragment, sizeof(log), &length, log);
			shader_print_errors("compile", log, source, num_source);

			GPU_shader_free(shader);
			return NULL;
		}
	}

	if (geocode) {
		const char *source[6];
		int num_source = 0;

		source[num_source++] = gpu_shader_version();
		source[num_source++] = standard_extensions;
		source[num_source++] = standard_defines;

		if (defines) source[num_source++] = defines;
		source[num_source++] = geocode;

		gpu_dump_shaders(source, num_source, DEBUG_SHADER_GEOMETRY);

		glAttachShader(shader->program, shader->geometry);
		glShaderSource(shader->geometry, num_source, source, NULL);

		glCompileShader(shader->geometry);
		glGetShaderiv(shader->geometry, GL_COMPILE_STATUS, &status);

		if (!status) {
			glGetShaderInfoLog(shader->geometry, sizeof(log), &length, log);
			shader_print_errors("compile", log, source, num_source);

			GPU_shader_free(shader);
			return NULL;
		}

		if (!use_opensubdiv) {
			GPU_shader_geometry_stage_primitive_io(shader, input, output, number);
		}
	}

#ifdef WITH_OPENSUBDIV
	if (use_opensubdiv) {
		glBindAttribLocation(shader->program, 0, "position");
		glBindAttribLocation(shader->program, 1, "normal");
		GPU_shader_geometry_stage_primitive_io(shader,
		                                       GL_LINES_ADJACENCY_EXT,
		                                       GL_TRIANGLE_STRIP,
		                                       4);
	}
#endif

	glLinkProgram(shader->program);
	glGetProgramiv(shader->program, GL_LINK_STATUS, &status);
	if (!status) {
		glGetProgramInfoLog(shader->program, sizeof(log), &length, log);
		/* print attached shaders in pipeline order */
		if (vertexcode) shader_print_errors("linking", log, &vertexcode, 1);
		if (geocode) shader_print_errors("linking", log, &geocode, 1);
		if (libcode) shader_print_errors("linking", log, &libcode, 1);
		if (fragcode) shader_print_errors("linking", log, &fragcode, 1);

		GPU_shader_free(shader);
		return NULL;
	}

#ifdef WITH_OPENSUBDIV
	/* TODO(sergey): Find a better place for this. */
	if (use_opensubdiv && GLEW_VERSION_4_1) {
		glProgramUniform1i(shader->program,
		                   glGetUniformLocation(shader->program, "FVarDataOffsetBuffer"),
		                   30);  /* GL_TEXTURE30 */

		glProgramUniform1i(shader->program,
		                   glGetUniformLocation(shader->program, "FVarDataBuffer"),
		                   31);  /* GL_TEXTURE31 */
	}
#endif

	return shader;
}
Ejemplo n.º 2
0
bool GPU_fx_compositor_initialize_passes(
        GPUFX *fx, const rcti *rect, const rcti *scissor_rect,
        const GPUFXSettings *fx_settings)
{
	int w = BLI_rcti_size_x(rect), h = BLI_rcti_size_y(rect);
	char err_out[256];
	int num_passes = 0;
	char fx_flag;

	fx->effects = 0;

	if (!GLEW_EXT_framebuffer_object)
		return false;

	if (!fx_settings) {
		cleanup_fx_gl_data(fx, true);
		return false;
	}

	fx_flag = fx_settings->fx_flag;

	/* disable effects if no options passed for them */
	if (!fx_settings->dof) {
		fx_flag &= ~GPU_FX_FLAG_DOF;
	}
	if (!fx_settings->ssao || fx_settings->ssao->samples < 1) {
		fx_flag &= ~GPU_FX_FLAG_SSAO;
	}

	if (!fx_flag) {
		cleanup_fx_gl_data(fx, true);
		return false;
	}

	/* scissor is missing when drawing offscreen, in that case, dimensions match exactly. In opposite case
	 * add one to match viewport dimensions */
	if (scissor_rect) {
		w++;
		h++;
	}

	fx->num_passes = 0;
	/* dof really needs a ping-pong buffer to work */
	if (fx_flag & GPU_FX_FLAG_DOF)
		num_passes++;

	if (fx_flag & GPU_FX_FLAG_SSAO)
		num_passes++;

	if (!fx->gbuffer) {
		fx->gbuffer = GPU_framebuffer_create();

		if (!fx->gbuffer) {
			return false;
		}
	}

	/* try creating the jitter texture */
	if (!fx->jitter_buffer)
		fx->jitter_buffer = create_jitter_texture();

	/* check if color buffers need recreation */
	if (!fx->color_buffer || !fx->depth_buffer || w != fx->gbuffer_dim[0] || h != fx->gbuffer_dim[1]) {
		cleanup_fx_gl_data(fx, false);

		if (!(fx->color_buffer = GPU_texture_create_2D(w, h, NULL, GPU_HDR_NONE, err_out))) {
			printf(".256%s\n", err_out);
			cleanup_fx_gl_data(fx, true);
			return false;
		}

		if (!(fx->depth_buffer = GPU_texture_create_depth(w, h, err_out))) {
			printf("%.256s\n", err_out);
			cleanup_fx_gl_data(fx, true);
			return false;
		}
	}

	if (fx_flag & GPU_FX_FLAG_SSAO) {
		if (fx_settings->ssao->samples != fx->ssao_sample_count_cache || !fx->ssao_spiral_samples_tex) {
			if (fx_settings->ssao->samples < 1)
				fx_settings->ssao->samples = 1;

			fx->ssao_sample_count_cache = fx_settings->ssao->samples;

			if (fx->ssao_spiral_samples_tex) {
				GPU_texture_free(fx->ssao_spiral_samples_tex);
			}

			fx->ssao_spiral_samples_tex = create_spiral_sample_texture(fx_settings->ssao->samples);
		}
	}
	else {
		if (fx->ssao_spiral_samples_tex) {
			GPU_texture_free(fx->ssao_spiral_samples_tex);
			fx->ssao_spiral_samples_tex = NULL;
		}
	}

	/* create textures for dof effect */
	if (fx_flag & GPU_FX_FLAG_DOF) {
		bool dof_high_quality = (fx_settings->dof->high_quality != 0) &&
		                        GPU_geometry_shader_support() && GPU_instanced_drawing_support();

		/* cleanup buffers if quality setting has changed (no need to keep more buffers around than necessary ) */
		if (dof_high_quality != fx->dof_high_quality)
			cleanup_fx_dof_buffers(fx);

		if (dof_high_quality) {
			fx->dof_downsampled_w = w / 2;
			fx->dof_downsampled_h = h / 2;

			if (!fx->dof_half_downsampled_near || !fx->dof_nearfar_coc || !fx->dof_near_blur ||
			    !fx->dof_far_blur || !fx->dof_half_downsampled_far)
			{

				if (!(fx->dof_half_downsampled_near = GPU_texture_create_2D(
				      fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out)))
				{
					printf("%.256s\n", err_out);
					cleanup_fx_gl_data(fx, true);
					return false;
				}
				if (!(fx->dof_half_downsampled_far = GPU_texture_create_2D(
				      fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out)))
				{
					printf("%.256s\n", err_out);
					cleanup_fx_gl_data(fx, true);
					return false;
				}
				if (!(fx->dof_nearfar_coc = GPU_texture_create_2D_procedural(
				      fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, false, err_out)))
				{
					printf("%.256s\n", err_out);
					cleanup_fx_gl_data(fx, true);
					return false;
				}


				if (!(fx->dof_near_blur = GPU_texture_create_2D(
				    fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_HALF_FLOAT, err_out)))
				{
					printf("%.256s\n", err_out);
					cleanup_fx_gl_data(fx, true);
					return false;
				}

				if (!(fx->dof_far_blur = GPU_texture_create_2D(
				    fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_HALF_FLOAT, err_out)))
				{
					printf("%.256s\n", err_out);
					cleanup_fx_gl_data(fx, true);
					return false;
				}
			}
		}
		else {
			fx->dof_downsampled_w = w / 4;
			fx->dof_downsampled_h = h / 4;

			if (!fx->dof_near_coc_buffer || !fx->dof_near_coc_blurred_buffer || !fx->dof_near_coc_final_buffer) {

				if (!(fx->dof_near_coc_buffer = GPU_texture_create_2D(
				          fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out)))
				{
					printf("%.256s\n", err_out);
					cleanup_fx_gl_data(fx, true);
					return false;
				}
				if (!(fx->dof_near_coc_blurred_buffer = GPU_texture_create_2D(
				          fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out)))
				{
					printf("%.256s\n", err_out);
					cleanup_fx_gl_data(fx, true);
					return false;
				}
				if (!(fx->dof_near_coc_final_buffer = GPU_texture_create_2D(
				          fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out)))
				{
					printf("%.256s\n", err_out);
					cleanup_fx_gl_data(fx, true);
					return false;
				}
			}
		}

		fx->dof_high_quality = dof_high_quality;
	}
	else {
		/* cleanup unnecessary buffers */
		cleanup_fx_dof_buffers(fx);
	}

	/* we need to pass data between shader stages, allocate an extra color buffer */
	if (num_passes > 1) {
		if (!fx->color_buffer_sec) {
			if (!(fx->color_buffer_sec = GPU_texture_create_2D(w, h, NULL, GPU_HDR_NONE, err_out))) {
				printf(".256%s\n", err_out);
				cleanup_fx_gl_data(fx, true);
				return false;
			}
		}
	}
	else {
		if (fx->color_buffer_sec) {
			GPU_framebuffer_texture_detach(fx->color_buffer_sec);
			GPU_texture_free(fx->color_buffer_sec);
			fx->color_buffer_sec = NULL;
		}
	}

	/* bind the buffers */

	/* first depth buffer, because system assumes read/write buffers */
	if (!GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer, 0, err_out))
		printf("%.256s\n", err_out);

	if (!GPU_framebuffer_texture_attach(fx->gbuffer, fx->color_buffer, 0, err_out))
		printf("%.256s\n", err_out);

	if (!GPU_framebuffer_check_valid(fx->gbuffer, err_out))
		printf("%.256s\n", err_out);

	GPU_texture_bind_as_framebuffer(fx->color_buffer);

	/* enable scissor test. It's needed to ensure sculpting works correctly */
	if (scissor_rect) {
		int w_sc = BLI_rcti_size_x(scissor_rect) + 1;
		int h_sc = BLI_rcti_size_y(scissor_rect) + 1;
		glPushAttrib(GL_SCISSOR_BIT);
		glEnable(GL_SCISSOR_TEST);
		glScissor(scissor_rect->xmin - rect->xmin, scissor_rect->ymin - rect->ymin,
		          w_sc, h_sc);
		fx->restore_stencil = true;
	}
	else {
		fx->restore_stencil = false;
	}

	fx->effects = fx_flag;

	if (fx_settings)
		fx->settings = *fx_settings;
	fx->gbuffer_dim[0] = w;
	fx->gbuffer_dim[1] = h;

	fx->num_passes = num_passes;

	return true;
}