1 #include "glsl_optimizer.h"
2 #include "ast.h"
3 #include "glsl_parser_extras.h"
4 #include "glsl_parser.h"
5 #include "ir_optimization.h"
6 #include "ir_print_metal_visitor.h"
7 #include "ir_print_glsl_visitor.h"
8 #include "ir_print_visitor.h"
9 #include "ir_stats.h"
10 #include "loop_analysis.h"
11 #include "program.h"
12 #include "linker.h"
13 #include "standalone_scaffolding.h"
14 
15 
16 extern "C" struct gl_shader *
17 _mesa_new_shader(struct gl_context *ctx, GLuint name, GLenum type);
18 
DeleteShader(struct gl_context * ctx,struct gl_shader * shader)19 static void DeleteShader(struct gl_context *ctx, struct gl_shader *shader)
20 {
21 	ralloc_free(shader);
22 }
23 
24 
25 static void
initialize_mesa_context(struct gl_context * ctx,glslopt_target api)26 initialize_mesa_context(struct gl_context *ctx, glslopt_target api)
27 {
28 	gl_api mesaAPI;
29 	switch(api)
30 	{
31 		default:
32 		case kGlslTargetOpenGL:
33 			mesaAPI = API_OPENGL_COMPAT;
34 			break;
35 		case kGlslTargetOpenGLES20:
36 			mesaAPI = API_OPENGLES2;
37 			break;
38 		case kGlslTargetOpenGLES30:
39 			mesaAPI = API_OPENGL_CORE;
40 			break;
41 		case kGlslTargetMetal:
42 			mesaAPI = API_OPENGL_CORE;
43 			break;
44 	}
45 	initialize_context_to_defaults (ctx, mesaAPI);
46 
47 	switch(api)
48 	{
49 	default:
50 	case kGlslTargetOpenGL:
51 		ctx->Const.GLSLVersion = 150;
52 		break;
53 	case kGlslTargetOpenGLES20:
54 		ctx->Extensions.OES_standard_derivatives = true;
55 		ctx->Extensions.EXT_shadow_samplers = true;
56 		ctx->Extensions.EXT_frag_depth = true;
57 		ctx->Extensions.EXT_shader_framebuffer_fetch = true;
58 		break;
59 	case kGlslTargetOpenGLES30:
60 		ctx->Extensions.ARB_ES3_compatibility = true;
61 		ctx->Extensions.EXT_shader_framebuffer_fetch = true;
62 		break;
63 	case kGlslTargetMetal:
64 		ctx->Const.GLSLVersion = 150;
65 		ctx->Extensions.ARB_ES3_compatibility = true;
66 		ctx->Extensions.EXT_shader_framebuffer_fetch = true;
67 		break;
68 	}
69 
70 
71    // allow high amount of texcoords
72    ctx->Const.MaxTextureCoordUnits = 16;
73 
74    ctx->Const.Program[MESA_SHADER_VERTEX].MaxTextureImageUnits = 16;
75    ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxTextureImageUnits = 16;
76    ctx->Const.Program[MESA_SHADER_GEOMETRY].MaxTextureImageUnits = 16;
77 
78    // For GLES2.0 this would be 1, but we do support GL_EXT_draw_buffers
79    ctx->Const.MaxDrawBuffers = 8;
80 
81    ctx->Driver.NewShader = _mesa_new_shader;
82    ctx->Driver.DeleteShader = DeleteShader;
83 }
84 
85 
86 struct glslopt_ctx {
glslopt_ctxglslopt_ctx87 	glslopt_ctx (glslopt_target target) {
88 		this->target = target;
89 		mem_ctx = ralloc_context (NULL);
90 		initialize_mesa_context (&mesa_ctx, target);
91 	}
~glslopt_ctxglslopt_ctx92 	~glslopt_ctx() {
93 		ralloc_free (mem_ctx);
94 	}
95 	struct gl_context mesa_ctx;
96 	void* mem_ctx;
97 	glslopt_target target;
98 };
99 
glslopt_initialize(glslopt_target target)100 glslopt_ctx* glslopt_initialize (glslopt_target target)
101 {
102 	return new glslopt_ctx(target);
103 }
104 
glslopt_cleanup(glslopt_ctx * ctx)105 void glslopt_cleanup (glslopt_ctx* ctx)
106 {
107 	delete ctx;
108 	_mesa_destroy_shader_compiler();
109 }
110 
glslopt_set_max_unroll_iterations(glslopt_ctx * ctx,unsigned iterations)111 void glslopt_set_max_unroll_iterations (glslopt_ctx* ctx, unsigned iterations)
112 {
113 	for (int i = 0; i < MESA_SHADER_STAGES; ++i)
114 		ctx->mesa_ctx.Const.ShaderCompilerOptions[i].MaxUnrollIterations = iterations;
115 }
116 
117 struct glslopt_shader_var
118 {
119 	const char* name;
120 	glslopt_basic_type type;
121 	glslopt_precision prec;
122 	int vectorSize;
123 	int matrixSize;
124 	int arraySize;
125 	int location;
126 };
127 
128 struct glslopt_shader
129 {
operator newglslopt_shader130 	static void* operator new(size_t size, void *ctx)
131 	{
132 		void *node;
133 		node = ralloc_size(ctx, size);
134 		assert(node != NULL);
135 		return node;
136 	}
operator deleteglslopt_shader137 	static void operator delete(void *node)
138 	{
139 		ralloc_free(node);
140 	}
141 
glslopt_shaderglslopt_shader142 	glslopt_shader ()
143 		: rawOutput(0)
144 		, optimizedOutput(0)
145 		, status(false)
146 		, uniformCount(0)
147 		, uniformsSize(0)
148 		, inputCount(0)
149 		, textureCount(0)
150 		, statsMath(0)
151 		, statsTex(0)
152 		, statsFlow(0)
153 	{
154 		infoLog = "Shader not compiled yet";
155 
156 		whole_program = rzalloc (NULL, struct gl_shader_program);
157 		assert(whole_program != NULL);
158 		whole_program->InfoLog = ralloc_strdup(whole_program, "");
159 
160 		whole_program->Shaders = reralloc(whole_program, whole_program->Shaders, struct gl_shader *, whole_program->NumShaders + 1);
161 		assert(whole_program->Shaders != NULL);
162 
163 		shader = rzalloc(whole_program, gl_shader);
164 		whole_program->Shaders[whole_program->NumShaders] = shader;
165 		whole_program->NumShaders++;
166 
167 		whole_program->LinkStatus = true;
168 	}
169 
~glslopt_shaderglslopt_shader170 	~glslopt_shader()
171 	{
172 		for (unsigned i = 0; i < MESA_SHADER_STAGES; i++)
173 			ralloc_free(whole_program->_LinkedShaders[i]);
174 		for(GLuint i =0;i< whole_program->NumShaders;i++)
175 			ralloc_free(whole_program->Shaders[i]);
176 		ralloc_free(whole_program->Shaders);
177 		ralloc_free(whole_program->InfoLog);
178 		ralloc_free(whole_program);
179 		ralloc_free(rawOutput);
180 		ralloc_free(optimizedOutput);
181 	}
182 
183 	struct gl_shader_program* whole_program;
184 	struct gl_shader* shader;
185 
186 	static const int kMaxShaderUniforms = 1024;
187 	static const int kMaxShaderInputs = 128;
188 	static const int kMaxShaderTextures = 128;
189 	glslopt_shader_var uniforms[kMaxShaderUniforms];
190 	glslopt_shader_var inputs[kMaxShaderInputs];
191 	glslopt_shader_var textures[kMaxShaderInputs];
192 	int uniformCount, uniformsSize;
193 	int inputCount;
194 	int textureCount;
195 	int statsMath, statsTex, statsFlow;
196 
197 	char*	rawOutput;
198 	char*	optimizedOutput;
199 	const char*	infoLog;
200 	bool	status;
201 };
202 
debug_print_ir(const char * name,exec_list * ir,_mesa_glsl_parse_state * state,void * memctx)203 static inline void debug_print_ir (const char* name, exec_list* ir, _mesa_glsl_parse_state* state, void* memctx)
204 {
205 	#if 0
206 	printf("**** %s:\n", name);
207 //	_mesa_print_ir (ir, state);
208 	char* foobar = _mesa_print_ir_glsl(ir, state, ralloc_strdup(memctx, ""), kPrintGlslFragment);
209 	printf("%s\n", foobar);
210 	validate_ir_tree(ir);
211 	#endif
212 }
213 
214 
215 struct precision_ctx
216 {
217 	exec_list* root_ir;
218 	bool res;
219 };
220 
221 
propagate_precision_deref(ir_instruction * ir,void * data)222 static void propagate_precision_deref(ir_instruction *ir, void *data)
223 {
224 	// variable deref with undefined precision: take from variable itself
225 	ir_dereference_variable* der = ir->as_dereference_variable();
226 	if (der && der->get_precision() == glsl_precision_undefined && der->var->data.precision != glsl_precision_undefined)
227 	{
228 		der->set_precision ((glsl_precision)der->var->data.precision);
229 		((precision_ctx*)data)->res = true;
230 	}
231 
232 	// array deref with undefined precision: take from array itself
233 	ir_dereference_array* der_arr = ir->as_dereference_array();
234 	if (der_arr && der_arr->get_precision() == glsl_precision_undefined && der_arr->array->get_precision() != glsl_precision_undefined)
235 	{
236 		der_arr->set_precision (der_arr->array->get_precision());
237 		((precision_ctx*)data)->res = true;
238 	}
239 
240 	// swizzle with undefined precision: take from swizzle argument
241 	ir_swizzle* swz = ir->as_swizzle();
242 	if (swz && swz->get_precision() == glsl_precision_undefined && swz->val->get_precision() != glsl_precision_undefined)
243 	{
244 		swz->set_precision (swz->val->get_precision());
245 		((precision_ctx*)data)->res = true;
246 	}
247 
248 }
249 
propagate_precision_expr(ir_instruction * ir,void * data)250 static void propagate_precision_expr(ir_instruction *ir, void *data)
251 {
252 	ir_expression* expr = ir->as_expression();
253 	if (!expr)
254 		return;
255 	if (expr->get_precision() != glsl_precision_undefined)
256 		return;
257 
258 	glsl_precision prec_params_max = glsl_precision_undefined;
259 	for (int i = 0; i < (int)expr->get_num_operands(); ++i)
260 	{
261 		ir_rvalue* op = expr->operands[i];
262 		if (op && op->get_precision() != glsl_precision_undefined)
263 			prec_params_max = higher_precision (prec_params_max, op->get_precision());
264 	}
265 	if (expr->get_precision() != prec_params_max)
266 	{
267 		expr->set_precision (prec_params_max);
268 		((precision_ctx*)data)->res = true;
269 	}
270 
271 }
272 
propagate_precision_texture(ir_instruction * ir,void * data)273 static void propagate_precision_texture(ir_instruction *ir, void *data)
274 {
275 	ir_texture* tex = ir->as_texture();
276 	if (!tex)
277 		return;
278 
279 	glsl_precision sampler_prec = tex->sampler->get_precision();
280 	if (tex->get_precision() == sampler_prec || sampler_prec == glsl_precision_undefined)
281 		return;
282 
283 	// set precision of ir_texture node to that of the sampler itself
284 	tex->set_precision(sampler_prec);
285 	((precision_ctx*)data)->res = true;
286 }
287 
propagate_precision_texture_metal(ir_instruction * ir,void * data)288 static void propagate_precision_texture_metal(ir_instruction* ir, void* data)
289 {
290 	// There are no precision specifiers in Metal
291 	ir_texture* tex = ir->as_texture();
292 	if (tex)
293 		tex->set_precision(glsl_precision_undefined);
294 }
295 
296 struct undefined_ass_ctx
297 {
298 	ir_variable* var;
299 	bool res;
300 };
301 
has_only_undefined_precision_assignments(ir_instruction * ir,void * data)302 static void has_only_undefined_precision_assignments(ir_instruction *ir, void *data)
303 {
304 	ir_assignment* ass = ir->as_assignment();
305 	if (!ass)
306 		return;
307 	undefined_ass_ctx* ctx = (undefined_ass_ctx*)data;
308 	if (ass->whole_variable_written() != ctx->var)
309 		return;
310 	glsl_precision prec = ass->rhs->get_precision();
311 	if (prec == glsl_precision_undefined)
312 		return;
313 	ctx->res = false;
314 }
315 
316 
propagate_precision_assign(ir_instruction * ir,void * data)317 static void propagate_precision_assign(ir_instruction *ir, void *data)
318 {
319 	ir_assignment* ass = ir->as_assignment();
320 	if (!ass || !ass->lhs || !ass->rhs)
321 		return;
322 
323 	glsl_precision lp = ass->lhs->get_precision();
324 	glsl_precision rp = ass->rhs->get_precision();
325 
326 	// for assignments with LHS having undefined precision, take it from RHS
327 	if (rp != glsl_precision_undefined)
328 	{
329 		ir_variable* lhs_var = ass->lhs->variable_referenced();
330 		if (lp == glsl_precision_undefined)
331 		{
332 			if (lhs_var)
333 				lhs_var->data.precision = rp;
334 			ass->lhs->set_precision (rp);
335 			((precision_ctx*)data)->res = true;
336 		}
337 		return;
338 	}
339 
340 	// for assignments where LHS has precision, but RHS is a temporary variable
341 	// with undefined precision that's only assigned from other undefined precision
342 	// sources -> make the RHS variable take LHS precision
343 	if (lp != glsl_precision_undefined && rp == glsl_precision_undefined)
344 	{
345 		ir_dereference* deref = ass->rhs->as_dereference();
346 		if (deref)
347 		{
348 			ir_variable* rhs_var = deref->variable_referenced();
349 			if (rhs_var && rhs_var->data.mode == ir_var_temporary && rhs_var->data.precision == glsl_precision_undefined)
350 			{
351 				undefined_ass_ctx ctx;
352 				ctx.var = rhs_var;
353 				// find if we only assign to it from undefined precision sources
354 				ctx.res = true;
355 				exec_list* root_ir = ((precision_ctx*)data)->root_ir;
356 				foreach_in_list(ir_instruction, inst, root_ir)
357 				{
358 					visit_tree (ir, has_only_undefined_precision_assignments, &ctx);
359 				}
360 				if (ctx.res)
361 				{
362 					rhs_var->data.precision = lp;
363 					ass->rhs->set_precision(lp);
364 					((precision_ctx*)data)->res = true;
365 				}
366 			}
367 		}
368 		return;
369 	}
370 }
371 
372 
propagate_precision_call(ir_instruction * ir,void * data)373 static void propagate_precision_call(ir_instruction *ir, void *data)
374 {
375 	ir_call* call = ir->as_call();
376 	if (!call)
377 		return;
378 	if (!call->return_deref)
379 		return;
380 	if (call->return_deref->get_precision() == glsl_precision_undefined /*&& call->callee->precision == glsl_precision_undefined*/)
381 	{
382 		glsl_precision prec_params_max = glsl_precision_undefined;
383 		foreach_two_lists(formal_node, &call->callee->parameters,
384 						  actual_node, &call->actual_parameters) {
385 			ir_variable* sig_param = (ir_variable*)formal_node;
386 			ir_rvalue* param = (ir_rvalue*)actual_node;
387 
388 			glsl_precision p = (glsl_precision)sig_param->data.precision;
389 			if (p == glsl_precision_undefined)
390 				p = param->get_precision();
391 
392 			prec_params_max = higher_precision (prec_params_max, p);
393 		}
394 		if (call->return_deref->get_precision() != prec_params_max)
395 		{
396 			call->return_deref->set_precision (prec_params_max);
397 			((precision_ctx*)data)->res = true;
398 		}
399 	}
400 }
401 
propagate_precision(exec_list * list,bool metal_target)402 static bool propagate_precision(exec_list* list, bool metal_target)
403 {
404 	bool anyProgress = false;
405 	precision_ctx ctx;
406 
407 	do {
408 		ctx.res = false;
409 		ctx.root_ir = list;
410 		foreach_in_list(ir_instruction, ir, list)
411 		{
412 			if (metal_target)
413 				visit_tree (ir, propagate_precision_texture_metal, &ctx);
414 			else
415 				visit_tree (ir, propagate_precision_texture, &ctx);
416 
417 			visit_tree (ir, propagate_precision_deref, &ctx);
418 			bool hadProgress = ctx.res;
419 			ctx.res = false;
420 			visit_tree (ir, propagate_precision_assign, &ctx);
421 			if (ctx.res)
422 			{
423 				// assignment precision propagation might have added precision
424 				// to some variables; need to propagate dereference precision right
425 				// after that too.
426 				visit_tree (ir, propagate_precision_deref, &ctx);
427 			}
428 			ctx.res |= hadProgress;
429 			visit_tree (ir, propagate_precision_call, &ctx);
430 			visit_tree (ir, propagate_precision_expr, &ctx);
431 		}
432 		anyProgress |= ctx.res;
433 	} while (ctx.res);
434 	anyProgress |= ctx.res;
435 
436 	// for globals that have undefined precision, set it to highp
437 	if (metal_target)
438 	{
439 		foreach_in_list(ir_instruction, ir, list)
440 		{
441 			ir_variable* var = ir->as_variable();
442 			if (var)
443 			{
444 				if (var->data.precision == glsl_precision_undefined)
445 				{
446 					var->data.precision = glsl_precision_high;
447 					anyProgress = true;
448 				}
449 			}
450 		}
451 	}
452 
453 	return anyProgress;
454 }
455 
456 
do_optimization_passes(exec_list * ir,bool linked,_mesa_glsl_parse_state * state,void * mem_ctx)457 static void do_optimization_passes(exec_list* ir, bool linked, _mesa_glsl_parse_state* state, void* mem_ctx)
458 {
459 	bool progress;
460 	// FIXME: Shouldn't need to bound the number of passes
461 	int passes = 0,
462 		kMaximumPasses = 1000;
463 	do {
464 		progress = false;
465 		++passes;
466 		bool progress2;
467 		debug_print_ir ("Initial", ir, state, mem_ctx);
468 		if (linked) {
469 			progress2 = do_function_inlining(ir); progress |= progress2; if (progress2) debug_print_ir ("After inlining", ir, state, mem_ctx);
470 			progress2 = do_dead_functions(ir); progress |= progress2; if (progress2) debug_print_ir ("After dead functions", ir, state, mem_ctx);
471 			progress2 = do_structure_splitting(ir); progress |= progress2; if (progress2) debug_print_ir ("After struct splitting", ir, state, mem_ctx);
472 		}
473 		progress2 = do_if_simplification(ir); progress |= progress2; if (progress2) debug_print_ir ("After if simpl", ir, state, mem_ctx);
474 		progress2 = opt_flatten_nested_if_blocks(ir); progress |= progress2; if (progress2) debug_print_ir ("After if flatten", ir, state, mem_ctx);
475 		progress2 = propagate_precision (ir, state->metal_target); progress |= progress2; if (progress2) debug_print_ir ("After prec propagation", ir, state, mem_ctx);
476 		progress2 = do_copy_propagation(ir); progress |= progress2; if (progress2) debug_print_ir ("After copy propagation", ir, state, mem_ctx);
477 		progress2 = do_copy_propagation_elements(ir); progress |= progress2; if (progress2) debug_print_ir ("After copy propagation elems", ir, state, mem_ctx);
478 
479 		if (linked)
480 		{
481 			progress2 = do_vectorize(ir); progress |= progress2; if (progress2) debug_print_ir ("After vectorize", ir, state, mem_ctx);
482 		}
483 		if (linked) {
484 			progress2 = do_dead_code(ir,false); progress |= progress2; if (progress2) debug_print_ir ("After dead code", ir, state, mem_ctx);
485 		} else {
486 			progress2 = do_dead_code_unlinked(ir); progress |= progress2; if (progress2) debug_print_ir ("After dead code unlinked", ir, state, mem_ctx);
487 		}
488 		progress2 = do_dead_code_local(ir); progress |= progress2; if (progress2) debug_print_ir ("After dead code local", ir, state, mem_ctx);
489 		progress2 = propagate_precision (ir, state->metal_target); progress |= progress2; if (progress2) debug_print_ir ("After prec propagation", ir, state, mem_ctx);
490 		progress2 = do_tree_grafting(ir); progress |= progress2; if (progress2) debug_print_ir ("After tree grafting", ir, state, mem_ctx);
491 		progress2 = do_constant_propagation(ir); progress |= progress2; if (progress2) debug_print_ir ("After const propagation", ir, state, mem_ctx);
492 		if (linked) {
493 			progress2 = do_constant_variable(ir); progress |= progress2; if (progress2) debug_print_ir ("After const variable", ir, state, mem_ctx);
494 		} else {
495 			progress2 = do_constant_variable_unlinked(ir); progress |= progress2; if (progress2) debug_print_ir ("After const variable unlinked", ir, state, mem_ctx);
496 		}
497 		progress2 = do_constant_folding(ir); progress |= progress2; if (progress2) debug_print_ir ("After const folding", ir, state, mem_ctx);
498 		progress2 = do_minmax_prune(ir); progress |= progress2; if (progress2) debug_print_ir ("After minmax prune", ir, state, mem_ctx);
499 		progress2 = do_cse(ir); progress |= progress2; if (progress2) debug_print_ir ("After CSE", ir, state, mem_ctx);
500 		progress2 = do_rebalance_tree(ir); progress |= progress2; if (progress2) debug_print_ir ("After rebalance tree", ir, state, mem_ctx);
501 		progress2 = do_algebraic(ir, state->ctx->Const.NativeIntegers, &state->ctx->Const.ShaderCompilerOptions[state->stage]); progress |= progress2; if (progress2) debug_print_ir ("After algebraic", ir, state, mem_ctx);
502 		progress2 = do_lower_jumps(ir); progress |= progress2; if (progress2) debug_print_ir ("After lower jumps", ir, state, mem_ctx);
503 		progress2 = do_vec_index_to_swizzle(ir); progress |= progress2; if (progress2) debug_print_ir ("After vec index to swizzle", ir, state, mem_ctx);
504 		progress2 = lower_vector_insert(ir, false); progress |= progress2; if (progress2) debug_print_ir ("After lower vector insert", ir, state, mem_ctx);
505 		progress2 = do_swizzle_swizzle(ir); progress |= progress2; if (progress2) debug_print_ir ("After swizzle swizzle", ir, state, mem_ctx);
506 		progress2 = do_noop_swizzle(ir); progress |= progress2; if (progress2) debug_print_ir ("After noop swizzle", ir, state, mem_ctx);
507 		progress2 = optimize_split_arrays(ir, linked, state->metal_target && state->stage == MESA_SHADER_FRAGMENT); progress |= progress2; if (progress2) debug_print_ir ("After split arrays", ir, state, mem_ctx);
508 		progress2 = optimize_redundant_jumps(ir); progress |= progress2; if (progress2) debug_print_ir ("After redundant jumps", ir, state, mem_ctx);
509 
510 		// do loop stuff only when linked; otherwise causes duplicate loop induction variable
511 		// problems (ast-in.txt test)
512 		if (linked)
513 		{
514 			loop_state *ls = analyze_loop_variables(ir);
515 			if (ls->loop_found) {
516 				progress2 = set_loop_controls(ir, ls); progress |= progress2; if (progress2) debug_print_ir ("After set loop", ir, state, mem_ctx);
517 				progress2 = unroll_loops(ir, ls, &state->ctx->Const.ShaderCompilerOptions[state->stage]); progress |= progress2; if (progress2) debug_print_ir ("After unroll", ir, state, mem_ctx);
518 			}
519 			delete ls;
520 		}
521 	} while (progress && passes < kMaximumPasses);
522 
523 	if (!state->metal_target)
524 	{
525 		// GLSL/ES does not have saturate, so lower it
526 		lower_instructions(ir, SAT_TO_CLAMP);
527 	}
528 }
529 
glsl_type_to_optimizer_desc(const glsl_type * type,glsl_precision prec,glslopt_shader_var * out)530 static void glsl_type_to_optimizer_desc(const glsl_type* type, glsl_precision prec, glslopt_shader_var* out)
531 {
532 	out->arraySize = type->array_size();
533 
534 	// type; use element type when in array
535 	if (type->is_array())
536 		type = type->element_type();
537 
538 	if (type->is_float())
539 		out->type = kGlslTypeFloat;
540 	else if (type->is_integer())
541 		out->type = kGlslTypeInt;
542 	else if (type->is_boolean())
543 		out->type = kGlslTypeBool;
544 	else if (type->is_sampler())
545 	{
546 		if (type->sampler_dimensionality == GLSL_SAMPLER_DIM_2D)
547 		{
548 			if (type->sampler_shadow)
549 				out->type = kGlslTypeTex2DShadow;
550 			else if (type->sampler_array)
551 				out->type = kGlslTypeTex2DArray;
552 			else
553 				out->type = kGlslTypeTex2D;
554 		}
555 		else if (type->sampler_dimensionality == GLSL_SAMPLER_DIM_3D)
556 			out->type = kGlslTypeTex3D;
557 		else if (type->sampler_dimensionality == GLSL_SAMPLER_DIM_CUBE)
558 			out->type = kGlslTypeTexCube;
559 		else
560 			out->type = kGlslTypeOther;
561 	}
562 	else
563 		out->type = kGlslTypeOther;
564 
565 	// sizes
566 	out->vectorSize = type->vector_elements;
567 	out->matrixSize = type->matrix_columns;
568 
569 	// precision
570 	switch (prec)
571 	{
572 		case glsl_precision_high: out->prec = kGlslPrecHigh; break;
573 		case glsl_precision_medium: out->prec = kGlslPrecMedium; break;
574 		case glsl_precision_low: out->prec = kGlslPrecLow; break;
575 		default: out->prec = kGlslPrecHigh; break;
576 	}
577 }
578 
find_shader_variables(glslopt_shader * sh,exec_list * ir)579 static void find_shader_variables(glslopt_shader* sh, exec_list* ir)
580 {
581 	foreach_in_list(ir_instruction, node, ir)
582 	{
583 		ir_variable* const var = node->as_variable();
584 		if (var == NULL)
585 			continue;
586 		if (var->data.mode == ir_var_shader_in)
587 		{
588 			if (sh->inputCount >= glslopt_shader::kMaxShaderInputs)
589 				continue;
590 
591 			glslopt_shader_var& v = sh->inputs[sh->inputCount];
592 			v.name = ralloc_strdup(sh, var->name);
593 			glsl_type_to_optimizer_desc(var->type, (glsl_precision)var->data.precision, &v);
594 			v.location = var->data.explicit_location ? var->data.location : -1;
595 			++sh->inputCount;
596 		}
597 		if (var->data.mode == ir_var_uniform && !var->type->is_sampler())
598 		{
599 			if (sh->uniformCount >= glslopt_shader::kMaxShaderUniforms)
600 				continue;
601 
602 			glslopt_shader_var& v = sh->uniforms[sh->uniformCount];
603 			v.name = ralloc_strdup(sh, var->name);
604 			glsl_type_to_optimizer_desc(var->type, (glsl_precision)var->data.precision, &v);
605 			v.location = var->data.explicit_location ? var->data.location : -1;
606 			++sh->uniformCount;
607 		}
608 		if (var->data.mode == ir_var_uniform && var->type->is_sampler())
609 		{
610 			if (sh->textureCount >= glslopt_shader::kMaxShaderTextures)
611 				continue;
612 
613 			glslopt_shader_var& v = sh->textures[sh->textureCount];
614 			v.name = ralloc_strdup(sh, var->name);
615 			glsl_type_to_optimizer_desc(var->type, (glsl_precision)var->data.precision, &v);
616 			v.location = var->data.explicit_location ? var->data.location : -1;
617 			++sh->textureCount;
618 		}
619 	}
620 }
621 
622 
glslopt_optimize(glslopt_ctx * ctx,glslopt_shader_type type,const char * shaderSource,unsigned options)623 glslopt_shader* glslopt_optimize (glslopt_ctx* ctx, glslopt_shader_type type, const char* shaderSource, unsigned options)
624 {
625 	glslopt_shader* shader = new (ctx->mem_ctx) glslopt_shader ();
626 
627 	PrintGlslMode printMode = kPrintGlslVertex;
628 	switch (type) {
629 	case kGlslOptShaderVertex:
630 			shader->shader->Type = GL_VERTEX_SHADER;
631 			shader->shader->Stage = MESA_SHADER_VERTEX;
632 			printMode = kPrintGlslVertex;
633 			break;
634 	case kGlslOptShaderFragment:
635 			shader->shader->Type = GL_FRAGMENT_SHADER;
636 			shader->shader->Stage = MESA_SHADER_FRAGMENT;
637 			printMode = kPrintGlslFragment;
638 			break;
639 	case kGlslOptShaderCompute:
640 			shader->shader->Type = GL_COMPUTE_SHADER;
641 			shader->shader->Stage = MESA_SHADER_COMPUTE;
642 			printMode = kPrintGlslFragment;
643 			break;
644 
645 	}
646 	if (!shader->shader->Type)
647 	{
648 		shader->infoLog = ralloc_asprintf (shader, "Unknown shader type %d", (int)type);
649 		shader->status = false;
650 		return shader;
651 	}
652 
653 	_mesa_glsl_parse_state* state = new (shader) _mesa_glsl_parse_state (&ctx->mesa_ctx, shader->shader->Stage, shader);
654 	if (ctx->target == kGlslTargetMetal)
655 		state->metal_target = true;
656 	state->error = 0;
657 
658 	if (!(options & kGlslOptionSkipPreprocessor))
659 	{
660 		state->error = !!glcpp_preprocess (state, &shaderSource, &state->info_log, state->extensions, &ctx->mesa_ctx);
661 		if (state->error)
662 		{
663 			shader->status = !state->error;
664 			shader->infoLog = state->info_log;
665 			return shader;
666 		}
667 	}
668 
669 	_mesa_glsl_lexer_ctor (state, shaderSource);
670 	_mesa_glsl_parse (state);
671 	_mesa_glsl_lexer_dtor (state);
672 
673 	exec_list* ir = new (shader) exec_list();
674 	shader->shader->ir = ir;
675 
676 	if (!state->error && !state->translation_unit.is_empty())
677 		_mesa_ast_to_hir (ir, state);
678 
679 	// Un-optimized output
680 	if (!state->error) {
681 		validate_ir_tree(ir);
682 		if (ctx->target == kGlslTargetMetal)
683 			shader->rawOutput = _mesa_print_ir_metal(ir, state, ralloc_strdup(shader, ""), printMode, &shader->uniformsSize);
684 		else
685 			shader->rawOutput = _mesa_print_ir_glsl(ir, state, ralloc_strdup(shader, ""), printMode);
686 	}
687 
688 	// Link built-in functions
689 	shader->shader->symbols = state->symbols;
690 	shader->shader->uses_builtin_functions = state->uses_builtin_functions;
691 
692 	struct gl_shader* linked_shader = NULL;
693 
694 	if (!state->error && !ir->is_empty() && !(options & kGlslOptionNotFullShader))
695 	{
696 		linked_shader = link_intrastage_shaders(shader,
697 												&ctx->mesa_ctx,
698 												shader->whole_program,
699 												shader->whole_program->Shaders,
700 												shader->whole_program->NumShaders);
701 		if (!linked_shader)
702 		{
703 			shader->status = false;
704 			shader->infoLog = shader->whole_program->InfoLog;
705 			return shader;
706 		}
707 		ir = linked_shader->ir;
708 
709 		debug_print_ir ("==== After link ====", ir, state, shader);
710 	}
711 
712 	// Do optimization post-link
713 	if (!state->error && !ir->is_empty())
714 	{
715 		const bool linked = !(options & kGlslOptionNotFullShader);
716 		do_optimization_passes(ir, linked, state, shader);
717 		validate_ir_tree(ir);
718 	}
719 
720 	// Final optimized output
721 	if (!state->error)
722 	{
723 		if (ctx->target == kGlslTargetMetal)
724 			shader->optimizedOutput = _mesa_print_ir_metal(ir, state, ralloc_strdup(shader, ""), printMode, &shader->uniformsSize);
725 		else
726 			shader->optimizedOutput = _mesa_print_ir_glsl(ir, state, ralloc_strdup(shader, ""), printMode);
727 	}
728 
729 	shader->status = !state->error;
730 	shader->infoLog = state->info_log;
731 
732 	find_shader_variables (shader, ir);
733 	if (!state->error)
734 		calculate_shader_stats (ir, &shader->statsMath, &shader->statsTex, &shader->statsFlow);
735 
736 	ralloc_free (ir);
737 	ralloc_free (state);
738 
739 	if (linked_shader)
740 		ralloc_free(linked_shader);
741 
742 	return shader;
743 }
744 
glslopt_shader_delete(glslopt_shader * shader)745 void glslopt_shader_delete (glslopt_shader* shader)
746 {
747 	delete shader;
748 }
749 
glslopt_get_status(glslopt_shader * shader)750 bool glslopt_get_status (glslopt_shader* shader)
751 {
752 	return shader->status;
753 }
754 
glslopt_get_output(glslopt_shader * shader)755 const char* glslopt_get_output (glslopt_shader* shader)
756 {
757 	return shader->optimizedOutput;
758 }
759 
glslopt_get_raw_output(glslopt_shader * shader)760 const char* glslopt_get_raw_output (glslopt_shader* shader)
761 {
762 	return shader->rawOutput;
763 }
764 
glslopt_get_log(glslopt_shader * shader)765 const char* glslopt_get_log (glslopt_shader* shader)
766 {
767 	return shader->infoLog;
768 }
769 
glslopt_shader_get_input_count(glslopt_shader * shader)770 int glslopt_shader_get_input_count (glslopt_shader* shader)
771 {
772 	return shader->inputCount;
773 }
774 
glslopt_shader_get_uniform_count(glslopt_shader * shader)775 int glslopt_shader_get_uniform_count (glslopt_shader* shader)
776 {
777 	return shader->uniformCount;
778 }
779 
glslopt_shader_get_uniform_total_size(glslopt_shader * shader)780 int glslopt_shader_get_uniform_total_size (glslopt_shader* shader)
781 {
782 	return shader->uniformsSize;
783 }
784 
glslopt_shader_get_texture_count(glslopt_shader * shader)785 int glslopt_shader_get_texture_count (glslopt_shader* shader)
786 {
787 	return shader->textureCount;
788 }
789 
glslopt_shader_get_input_desc(glslopt_shader * shader,int index,const char ** outName,glslopt_basic_type * outType,glslopt_precision * outPrec,int * outVecSize,int * outMatSize,int * outArraySize,int * outLocation)790 void glslopt_shader_get_input_desc (glslopt_shader* shader, int index, const char** outName, glslopt_basic_type* outType, glslopt_precision* outPrec, int* outVecSize, int* outMatSize, int* outArraySize, int* outLocation)
791 {
792 	const glslopt_shader_var& v = shader->inputs[index];
793 	*outName = v.name;
794 	*outType = v.type;
795 	*outPrec = v.prec;
796 	*outVecSize = v.vectorSize;
797 	*outMatSize = v.matrixSize;
798 	*outArraySize = v.arraySize;
799 	*outLocation = v.location;
800 }
801 
glslopt_shader_get_uniform_desc(glslopt_shader * shader,int index,const char ** outName,glslopt_basic_type * outType,glslopt_precision * outPrec,int * outVecSize,int * outMatSize,int * outArraySize,int * outLocation)802 void glslopt_shader_get_uniform_desc (glslopt_shader* shader, int index, const char** outName, glslopt_basic_type* outType, glslopt_precision* outPrec, int* outVecSize, int* outMatSize, int* outArraySize, int* outLocation)
803 {
804 	const glslopt_shader_var& v = shader->uniforms[index];
805 	*outName = v.name;
806 	*outType = v.type;
807 	*outPrec = v.prec;
808 	*outVecSize = v.vectorSize;
809 	*outMatSize = v.matrixSize;
810 	*outArraySize = v.arraySize;
811 	*outLocation = v.location;
812 }
813 
glslopt_shader_get_texture_desc(glslopt_shader * shader,int index,const char ** outName,glslopt_basic_type * outType,glslopt_precision * outPrec,int * outVecSize,int * outMatSize,int * outArraySize,int * outLocation)814 void glslopt_shader_get_texture_desc (glslopt_shader* shader, int index, const char** outName, glslopt_basic_type* outType, glslopt_precision* outPrec, int* outVecSize, int* outMatSize, int* outArraySize, int* outLocation)
815 {
816 	const glslopt_shader_var& v = shader->textures[index];
817 	*outName = v.name;
818 	*outType = v.type;
819 	*outPrec = v.prec;
820 	*outVecSize = v.vectorSize;
821 	*outMatSize = v.matrixSize;
822 	*outArraySize = v.arraySize;
823 	*outLocation = v.location;
824 }
825 
glslopt_shader_get_stats(glslopt_shader * shader,int * approxMath,int * approxTex,int * approxFlow)826 void glslopt_shader_get_stats (glslopt_shader* shader, int* approxMath, int* approxTex, int* approxFlow)
827 {
828 	*approxMath = shader->statsMath;
829 	*approxTex = shader->statsTex;
830 	*approxFlow = shader->statsFlow;
831 }
832