#include <string.h>
#include <assert.h>
-#include "main/core.h" /* for struct gl_context */
#include "main/context.h"
#include "main/debug_output.h"
#include "main/formats.h"
static const unsigned known_desktop_glsl_versions[] =
- { 110, 120, 130, 140, 150, 330, 400, 410, 420, 430, 440, 450 };
+ { 110, 120, 130, 140, 150, 330, 400, 410, 420, 430, 440, 450, 460 };
static const unsigned known_desktop_gl_versions[] =
- { 20, 21, 30, 31, 32, 33, 40, 41, 42, 43, 44, 45 };
+ { 20, 21, 30, 31, 32, 33, 40, 41, 42, 43, 44, 45, 46 };
_mesa_glsl_parse_state::_mesa_glsl_parse_state(struct gl_context *_ctx,
gl_shader_stage stage,
void *mem_ctx)
: ctx(_ctx), cs_input_local_size_specified(false), cs_input_local_size(),
- switch_state()
+ switch_state(), warnings_enabled(true)
{
assert(stage < MESA_SHADER_STAGES);
this->stage = stage;
/* Set default language version and extensions */
this->language_version = 110;
this->forced_language_version = ctx->Const.ForceGLSLVersion;
- this->zero_init = ctx->Const.GLSLZeroInit;
+ if (ctx->Const.GLSLZeroInit == 1) {
+ this->zero_init = (1u << ir_var_auto) | (1u << ir_var_temporary) | (1u << ir_var_shader_out);
+ } else if (ctx->Const.GLSLZeroInit == 2) {
+ this->zero_init = (1u << ir_var_auto) | (1u << ir_var_temporary) | (1u << ir_var_function_out);
+ } else {
+ this->zero_init = 0;
+ }
this->gl_version = 20;
this->compat_shader = true;
this->es_shader = false;
this->Const.MaxVertexOutputComponents = ctx->Const.Program[MESA_SHADER_VERTEX].MaxOutputComponents;
this->Const.MaxGeometryInputComponents = ctx->Const.Program[MESA_SHADER_GEOMETRY].MaxInputComponents;
this->Const.MaxGeometryOutputComponents = ctx->Const.Program[MESA_SHADER_GEOMETRY].MaxOutputComponents;
+ this->Const.MaxGeometryShaderInvocations = ctx->Const.MaxGeometryShaderInvocations;
this->Const.MaxFragmentInputComponents = ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxInputComponents;
this->Const.MaxGeometryTextureImageUnits = ctx->Const.Program[MESA_SHADER_GEOMETRY].MaxTextureImageUnits;
this->Const.MaxGeometryOutputVertices = ctx->Const.MaxGeometryOutputVertices;
this->current_function = NULL;
this->toplevel_ir = NULL;
this->found_return = false;
+ this->found_begin_interlock = false;
+ this->found_end_interlock = false;
this->all_invariant = false;
this->user_structures = NULL;
this->num_user_structures = 0;
this->fs_early_fragment_tests = false;
this->fs_inner_coverage = false;
this->fs_post_depth_coverage = false;
+ this->fs_pixel_interlock_ordered = false;
+ this->fs_pixel_interlock_unordered = false;
+ this->fs_sample_interlock_ordered = false;
+ this->fs_sample_interlock_unordered = false;
this->fs_blend_support = 0;
memset(this->atomic_counter_offsets, 0,
sizeof(this->atomic_counter_offsets));
this->allow_extension_directive_midshader =
ctx->Const.AllowGLSLExtensionDirectiveMidShader;
+ this->allow_glsl_120_subset_in_110 =
+ ctx->Const.AllowGLSL120SubsetIn110;
+ this->allow_builtin_variable_redeclaration =
+ ctx->Const.AllowGLSLBuiltinVariableRedeclaration;
+ this->allow_layout_qualifier_on_function_parameter =
+ ctx->Const.AllowLayoutQualifiersOnFunctionParameters;
this->cs_input_local_size_variable_specified = false;
+
+ /* ARB_bindless_texture */
+ this->bindless_sampler_specified = false;
+ this->bindless_image_specified = false;
+ this->bound_sampler_specified = false;
+ this->bound_image_specified = false;
}
/**
this->language_version = version;
this->compat_shader = compat_token_present ||
+ (this->ctx->API == API_OPENGL_COMPAT &&
+ this->language_version == 140) ||
(!this->es_shader && this->language_version < 140);
bool supported = false;
/* Get the offset that the new message will be written to. */
int msg_offset = strlen(state->info_log);
- ralloc_asprintf_append(&state->info_log, "%u:%u(%u): %s: ",
- locp->source,
- locp->first_line,
- locp->first_column,
- error ? "error" : "warning");
+ if (locp->path) {
+ ralloc_asprintf_append(&state->info_log, "\"%s\"", locp->path);
+ } else {
+ ralloc_asprintf_append(&state->info_log, "%u", locp->source);
+ }
+ ralloc_asprintf_append(&state->info_log, ":%u(%u): %s: ",
+ locp->first_line, locp->first_column,
+ error ? "error" : "warning");
+
ralloc_vasprintf_append(&state->info_log, fmt, ap);
const char *const msg = &state->info_log[msg_offset];
_mesa_glsl_warning(const YYLTYPE *locp, _mesa_glsl_parse_state *state,
const char *fmt, ...)
{
- va_list ap;
+ if (state->warnings_enabled) {
+ va_list ap;
- va_start(ap, fmt);
- _mesa_glsl_msg(locp, state, MESA_DEBUG_TYPE_OTHER, fmt, ap);
- va_end(ap);
+ va_start(ap, fmt);
+ _mesa_glsl_msg(locp, state, MESA_DEBUG_TYPE_OTHER, fmt, ap);
+ va_end(ap);
+ }
}
/** Checks if the context supports a user-facing extension */
#define EXT(name_str, driver_cap, ...) \
-static MAYBE_UNUSED bool \
+static UNUSED bool \
has_##name_str(const struct gl_context *ctx, gl_api api, uint8_t version) \
{ \
return ctx->Extensions.driver_cap && (version >= \
EXT(ARB_ES3_1_compatibility),
EXT(ARB_ES3_2_compatibility),
EXT(ARB_arrays_of_arrays),
+ EXT(ARB_bindless_texture),
+ EXT(ARB_compatibility),
EXT(ARB_compute_shader),
EXT(ARB_compute_variable_group_size),
EXT(ARB_conservative_depth),
EXT(ARB_explicit_uniform_location),
EXT(ARB_fragment_coord_conventions),
EXT(ARB_fragment_layer_viewport),
+ EXT(ARB_fragment_shader_interlock),
EXT(ARB_gpu_shader5),
EXT(ARB_gpu_shader_fp64),
EXT(ARB_gpu_shader_int64),
EXT(ARB_separate_shader_objects),
EXT(ARB_shader_atomic_counter_ops),
EXT(ARB_shader_atomic_counters),
+ EXT(ARB_shader_ballot),
EXT(ARB_shader_bit_encoding),
EXT(ARB_shader_clock),
EXT(ARB_shader_draw_parameters),
EXT(ARB_shader_texture_lod),
EXT(ARB_shader_viewport_layer_array),
EXT(ARB_shading_language_420pack),
+ EXT(ARB_shading_language_include),
EXT(ARB_shading_language_packing),
EXT(ARB_tessellation_shader),
EXT(ARB_texture_cube_map_array),
/* OES extensions go here, sorted alphabetically.
*/
EXT(OES_EGL_image_external),
+ EXT(OES_EGL_image_external_essl3),
EXT(OES_geometry_point_size),
EXT(OES_geometry_shader),
EXT(OES_gpu_shader5),
/* All other extensions go here, sorted alphabetically.
*/
EXT(AMD_conservative_depth),
+ EXT(AMD_gpu_shader_int64),
EXT(AMD_shader_stencil_export),
EXT(AMD_shader_trinary_minmax),
+ EXT(AMD_texture_texture4),
EXT(AMD_vertex_shader_layer),
EXT(AMD_vertex_shader_viewport_index),
EXT(ANDROID_extension_pack_es31a),
EXT(EXT_blend_func_extended),
+ EXT(EXT_demote_to_helper_invocation),
EXT(EXT_frag_depth),
EXT(EXT_draw_buffers),
+ EXT(EXT_draw_instanced),
EXT(EXT_clip_cull_distance),
EXT(EXT_geometry_point_size),
EXT_AEP(EXT_geometry_shader),
+ EXT(EXT_gpu_shader4),
EXT_AEP(EXT_gpu_shader5),
EXT_AEP(EXT_primitive_bounding_box),
EXT(EXT_separate_shader_objects),
EXT(EXT_shader_framebuffer_fetch),
+ EXT(EXT_shader_framebuffer_fetch_non_coherent),
+ EXT(EXT_shader_group_vote),
+ EXT(EXT_shader_image_load_formatted),
+ EXT(EXT_shader_image_load_store),
+ EXT(EXT_shader_implicit_conversions),
EXT(EXT_shader_integer_mix),
EXT_AEP(EXT_shader_io_blocks),
EXT(EXT_shader_samples_identical),
EXT(EXT_texture_array),
EXT_AEP(EXT_texture_buffer),
EXT_AEP(EXT_texture_cube_map_array),
+ EXT(EXT_texture_query_lod),
+ EXT(EXT_texture_shadow_lod),
EXT(INTEL_conservative_rasterization),
+ EXT(INTEL_shader_atomic_float_minmax),
+ EXT(INTEL_shader_integer_functions2),
EXT(MESA_shader_integer_functions),
+ EXT(NV_compute_shader_derivatives),
+ EXT(NV_fragment_shader_interlock),
EXT(NV_image_formats),
+ EXT(NV_shader_atomic_float),
+ EXT(NV_viewport_array2),
};
#undef EXT
}
/* If the aggregate is a struct, recursively set its fields' types. */
- } else if (type->is_record()) {
+ } else if (type->is_struct()) {
exec_node *expr_node = ai->expressions.get_head_raw();
/* Iterate through the struct's fields. */
"an instance name are not allowed");
}
- uint64_t interface_type_mask;
+ ast_type_qualifier::bitset_t interface_type_mask;
struct ast_type_qualifier temp_type_qualifier;
/* Get a bitmask containing only the in/out/uniform/buffer
* production rule guarantees that only one bit will be set (and
* it will be in/out/uniform).
*/
- uint64_t block_interface_qualifier = q.flags.i;
+ ast_type_qualifier::bitset_t block_interface_qualifier = q.flags.i;
block->default_layout.flags.i |= block_interface_qualifier;
}
}
-void
+static void
_mesa_ast_type_qualifier_print(const struct ast_type_qualifier *q)
{
if (q->is_subroutine_decl())
}
+void
+ast_demote_statement::print(void) const
+{
+ printf("demote; ");
+}
+
+
void
ast_selection_statement::print(void) const
{
}
-ast_struct_specifier::ast_struct_specifier(void *lin_ctx, const char *identifier,
+ast_struct_specifier::ast_struct_specifier(const char *identifier,
ast_declarator_list *declarator_list)
+ : name(identifier), layout(NULL), declarations(), is_declaration(true),
+ type(NULL)
{
- if (identifier == NULL) {
- static mtx_t mutex = _MTX_INITIALIZER_NP;
- static unsigned anon_count = 1;
- unsigned count;
-
- mtx_lock(&mutex);
- count = anon_count++;
- mtx_unlock(&mutex);
-
- identifier = linear_asprintf(lin_ctx, "#anon_struct_%04x", count);
- }
- name = identifier;
this->declarations.push_degenerate_list_at_head(&declarator_list->link);
- is_declaration = true;
- layout = NULL;
}
void ast_subroutine_list::print(void) const
struct _mesa_glsl_parse_state *state)
{
/* Should have been prevented by the parser. */
- if (shader->Stage == MESA_SHADER_TESS_CTRL ||
- shader->Stage == MESA_SHADER_VERTEX) {
- assert(!state->in_qualifier->flags.i);
- } else if (shader->Stage != MESA_SHADER_GEOMETRY &&
- shader->Stage != MESA_SHADER_TESS_EVAL) {
+ if (shader->Stage != MESA_SHADER_GEOMETRY &&
+ shader->Stage != MESA_SHADER_TESS_EVAL &&
+ shader->Stage != MESA_SHADER_COMPUTE) {
assert(!state->in_qualifier->flags.i);
}
/* Should have been prevented by the parser. */
assert(!state->cs_input_local_size_specified);
assert(!state->cs_input_local_size_variable_specified);
+ assert(state->cs_derivative_group == DERIVATIVE_GROUP_NONE);
}
if (shader->Stage != MESA_SHADER_FRAGMENT) {
assert(!state->fs_early_fragment_tests);
assert(!state->fs_inner_coverage);
assert(!state->fs_post_depth_coverage);
+ assert(!state->fs_pixel_interlock_ordered);
+ assert(!state->fs_pixel_interlock_unordered);
+ assert(!state->fs_sample_interlock_ordered);
+ assert(!state->fs_sample_interlock_unordered);
}
for (unsigned i = 0; i < MAX_FEEDBACK_BUFFERS; i++) {
&invocations, false)) {
YYLTYPE loc = state->in_qualifier->invocations->get_location();
- if (invocations > MAX_GEOMETRY_SHADER_INVOCATIONS) {
+ if (invocations > state->Const.MaxGeometryShaderInvocations) {
_mesa_glsl_error(&loc, state,
"invocations (%d) exceeds "
"GL_MAX_GEOMETRY_SHADER_INVOCATIONS",
shader->info.Comp.LocalSizeVariable =
state->cs_input_local_size_variable_specified;
+
+ shader->info.Comp.DerivativeGroup = state->cs_derivative_group;
+
+ if (state->NV_compute_shader_derivatives_enable) {
+ /* We allow multiple cs_input_layout nodes, but do not store them in
+ * a convenient place, so for now live with an empty location error.
+ */
+ YYLTYPE loc = {0};
+ if (shader->info.Comp.DerivativeGroup == DERIVATIVE_GROUP_QUADS) {
+ if (shader->info.Comp.LocalSize[0] % 2 != 0) {
+ _mesa_glsl_error(&loc, state, "derivative_group_quadsNV must be used with a "
+ "local group size whose first dimension "
+ "is a multiple of 2\n");
+ }
+ if (shader->info.Comp.LocalSize[1] % 2 != 0) {
+ _mesa_glsl_error(&loc, state, "derivative_group_quadsNV must be used with a "
+ "local group size whose second dimension "
+ "is a multiple of 2\n");
+ }
+ } else if (shader->info.Comp.DerivativeGroup == DERIVATIVE_GROUP_LINEAR) {
+ if ((shader->info.Comp.LocalSize[0] *
+ shader->info.Comp.LocalSize[1] *
+ shader->info.Comp.LocalSize[2]) % 4 != 0) {
+ _mesa_glsl_error(&loc, state, "derivative_group_linearNV must be used with a "
+ "local group size whose total number of invocations "
+ "is a multiple of 4\n");
+ }
+ }
+ }
+
break;
case MESA_SHADER_FRAGMENT:
shader->EarlyFragmentTests = state->fs_early_fragment_tests;
shader->InnerCoverage = state->fs_inner_coverage;
shader->PostDepthCoverage = state->fs_post_depth_coverage;
+ shader->PixelInterlockOrdered = state->fs_pixel_interlock_ordered;
+ shader->PixelInterlockUnordered = state->fs_pixel_interlock_unordered;
+ shader->SampleInterlockOrdered = state->fs_sample_interlock_ordered;
+ shader->SampleInterlockUnordered = state->fs_sample_interlock_unordered;
shader->BlendSupport = state->fs_blend_support;
break;
/* Nothing to do. */
break;
}
+
+ shader->bindless_sampler = state->bindless_sampler_specified;
+ shader->bindless_image = state->bindless_image_specified;
+ shader->bound_sampler = state->bound_sampler_specified;
+ shader->bound_image = state->bound_image_specified;
+ shader->redeclares_gl_layer = state->redeclares_gl_layer;
+ shader->layer_viewport_relative = state->layer_viewport_relative;
+}
+
+/* src can be NULL if only the symbols found in the exec_list should be
+ * copied
+ */
+void
+_mesa_glsl_copy_symbols_from_table(struct exec_list *shader_ir,
+ struct glsl_symbol_table *src,
+ struct glsl_symbol_table *dest)
+{
+ foreach_in_list (ir_instruction, ir, shader_ir) {
+ switch (ir->ir_type) {
+ case ir_type_function:
+ dest->add_function((ir_function *) ir);
+ break;
+ case ir_type_variable: {
+ ir_variable *const var = (ir_variable *) ir;
+
+ if (var->data.mode != ir_var_temporary)
+ dest->add_variable(var);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ if (src != NULL) {
+ /* Explicitly copy the gl_PerVertex interface definitions because these
+ * are needed to check they are the same during the interstage link.
+ * They can’t necessarily be found via the exec_list because the members
+ * might not be referenced. The GL spec still requires that they match
+ * in that case.
+ */
+ const glsl_type *iface =
+ src->get_interface("gl_PerVertex", ir_var_shader_in);
+ if (iface)
+ dest->add_interface(iface->name, iface, ir_var_shader_in);
+
+ iface = src->get_interface("gl_PerVertex", ir_var_shader_out);
+ if (iface)
+ dest->add_interface(iface->name, iface, ir_var_shader_out);
+ }
}
extern "C" {
static void
-assign_subroutine_indexes(struct gl_shader *sh,
- struct _mesa_glsl_parse_state *state)
+assign_subroutine_indexes(struct _mesa_glsl_parse_state *state)
{
int j, k;
int index = 0;
}
}
+static void
+opt_shader_and_create_symbol_table(struct gl_context *ctx,
+ struct glsl_symbol_table *source_symbols,
+ struct gl_shader *shader)
+{
+ assert(shader->CompileStatus != COMPILE_FAILURE &&
+ !shader->ir->is_empty());
+
+ struct gl_shader_compiler_options *options =
+ &ctx->Const.ShaderCompilerOptions[shader->Stage];
+
+ /* Do some optimization at compile time to reduce shader IR size
+ * and reduce later work if the same shader is linked multiple times
+ */
+ if (ctx->Const.GLSLOptimizeConservatively) {
+ /* Run it just once. */
+ do_common_optimization(shader->ir, false, false, options,
+ ctx->Const.NativeIntegers);
+ } else {
+ /* Repeat it until it stops making changes. */
+ while (do_common_optimization(shader->ir, false, false, options,
+ ctx->Const.NativeIntegers))
+ ;
+ }
+
+ validate_ir_tree(shader->ir);
+
+ enum ir_variable_mode other;
+ switch (shader->Stage) {
+ case MESA_SHADER_VERTEX:
+ other = ir_var_shader_in;
+ break;
+ case MESA_SHADER_FRAGMENT:
+ other = ir_var_shader_out;
+ break;
+ default:
+ /* Something invalid to ensure optimize_dead_builtin_uniforms
+ * doesn't remove anything other than uniforms or constants.
+ */
+ other = ir_var_mode_count;
+ break;
+ }
+
+ optimize_dead_builtin_variables(shader->ir, other);
+
+ validate_ir_tree(shader->ir);
+
+ /* Retain any live IR, but trash the rest. */
+ reparent_ir(shader->ir, shader->ir);
+
+ /* Destroy the symbol table. Create a new symbol table that contains only
+ * the variables and functions that still exist in the IR. The symbol
+ * table will be used later during linking.
+ *
+ * There must NOT be any freed objects still referenced by the symbol
+ * table. That could cause the linker to dereference freed memory.
+ *
+ * We don't have to worry about types or interface-types here because those
+ * are fly-weights that are looked up by glsl_type.
+ */
+ _mesa_glsl_copy_symbols_from_table(shader->ir, source_symbols,
+ shader->symbols);
+}
+
+static bool
+can_skip_compile(struct gl_context *ctx, struct gl_shader *shader,
+ const char *source, bool force_recompile,
+ bool source_has_shader_include)
+{
+ if (!force_recompile) {
+ if (ctx->Cache) {
+ char buf[41];
+ disk_cache_compute_key(ctx->Cache, source, strlen(source),
+ shader->sha1);
+ if (disk_cache_has_key(ctx->Cache, shader->sha1)) {
+ /* We've seen this shader before and know it compiles */
+ if (ctx->_Shader->Flags & GLSL_CACHE_INFO) {
+ _mesa_sha1_format(buf, shader->sha1);
+ fprintf(stderr, "deferring compile of shader: %s\n", buf);
+ }
+ shader->CompileStatus = COMPILE_SKIPPED;
+
+ free((void *)shader->FallbackSource);
+
+ /* Copy pre-processed shader include to fallback source otherwise
+ * we have no guarantee the shader include source tree has not
+ * changed.
+ */
+ shader->FallbackSource = source_has_shader_include ?
+ strdup(source) : NULL;
+ return true;
+ }
+ }
+ } else {
+ /* We should only ever end up here if a re-compile has been forced by a
+ * shader cache miss. In which case we can skip the compile if its
+ * already been done by a previous fallback or the initial compile call.
+ */
+ if (shader->CompileStatus == COMPILE_SUCCESS)
+ return true;
+ }
+
+ return false;
+}
+
void
_mesa_glsl_compile_shader(struct gl_context *ctx, struct gl_shader *shader,
bool dump_ast, bool dump_hir, bool force_recompile)
{
- struct _mesa_glsl_parse_state *state =
- new(shader) _mesa_glsl_parse_state(ctx, shader->Stage, shader);
const char *source = force_recompile && shader->FallbackSource ?
shader->FallbackSource : shader->Source;
+ /* Note this will be true for shaders the have #include inside comments
+ * however that should be rare enough not to worry about.
+ */
+ bool source_has_shader_include =
+ strstr(source, "#include") == NULL ? false : true;
+
+ /* If there was no shader include we can check the shader cache and skip
+ * compilation before we run the preprocessor. We never skip compiling
+ * shaders that use ARB_shading_language_include because we would need to
+ * keep duplicate copies of the shader include source tree and paths.
+ */
+ if (!source_has_shader_include &&
+ can_skip_compile(ctx, shader, source, force_recompile, false))
+ return;
+
+ struct _mesa_glsl_parse_state *state =
+ new(shader) _mesa_glsl_parse_state(ctx, shader->Stage, shader);
+
if (ctx->Const.GenerateTemporaryNames)
(void) p_atomic_cmpxchg(&ir_variable::temporaries_allocate_names,
false, true);
- state->error = glcpp_preprocess(state, &source, &state->info_log,
- add_builtin_defines, state, ctx);
-
- if (!force_recompile) {
- char buf[41];
- _mesa_sha1_compute(source, strlen(source), shader->sha1);
- if (ctx->Cache && disk_cache_has_key(ctx->Cache, shader->sha1)) {
- /* We've seen this shader before and know it compiles */
- if (ctx->_Shader->Flags & GLSL_CACHE_INFO) {
- fprintf(stderr, "deferring compile of shader: %s\n",
- _mesa_sha1_format(buf, shader->sha1));
- }
- shader->CompileStatus = compile_skipped;
-
- free((void *)shader->FallbackSource);
- shader->FallbackSource = NULL;
- return;
- }
+ if (!source_has_shader_include || !force_recompile) {
+ state->error = glcpp_preprocess(state, &source, &state->info_log,
+ add_builtin_defines, state, ctx);
}
+ /* Now that we have run the preprocessor we can check the shader cache and
+ * skip compilation if possible for those shaders that contained a shader
+ * include.
+ */
+ if (source_has_shader_include &&
+ can_skip_compile(ctx, shader, source, force_recompile, true))
+ return;
+
if (!state->error) {
_mesa_glsl_lexer_ctor(state, source);
_mesa_glsl_parse(state);
}
}
-
- if (!state->error && !shader->ir->is_empty()) {
- struct gl_shader_compiler_options *options =
- &ctx->Const.ShaderCompilerOptions[shader->Stage];
-
- assign_subroutine_indexes(shader, state);
- lower_subroutine(shader->ir, state);
-
- /* Do some optimization at compile time to reduce shader IR size
- * and reduce later work if the same shader is linked multiple times
- */
- if (ctx->Const.GLSLOptimizeConservatively) {
- /* Run it just once. */
- do_common_optimization(shader->ir, false, false, options,
- ctx->Const.NativeIntegers);
- } else {
- /* Repeat it until it stops making changes. */
- while (do_common_optimization(shader->ir, false, false, options,
- ctx->Const.NativeIntegers))
- ;
- }
-
- validate_ir_tree(shader->ir);
-
- enum ir_variable_mode other;
- switch (shader->Stage) {
- case MESA_SHADER_VERTEX:
- other = ir_var_shader_in;
- break;
- case MESA_SHADER_FRAGMENT:
- other = ir_var_shader_out;
- break;
- default:
- /* Something invalid to ensure optimize_dead_builtin_uniforms
- * doesn't remove anything other than uniforms or constants.
- */
- other = ir_var_mode_count;
- break;
- }
-
- optimize_dead_builtin_variables(shader->ir, other);
-
- validate_ir_tree(shader->ir);
- }
-
if (shader->InfoLog)
ralloc_free(shader->InfoLog);
set_shader_inout_layout(shader, state);
shader->symbols = new(shader->ir) glsl_symbol_table;
- shader->CompileStatus = state->error ? compile_failure : compile_success;
+ shader->CompileStatus = state->error ? COMPILE_FAILURE : COMPILE_SUCCESS;
shader->InfoLog = state->info_log;
shader->Version = state->language_version;
shader->IsES = state->es_shader;
- /* Retain any live IR, but trash the rest. */
- reparent_ir(shader->ir, shader->ir);
+ struct gl_shader_compiler_options *options =
+ &ctx->Const.ShaderCompilerOptions[shader->Stage];
- /* Destroy the symbol table. Create a new symbol table that contains only
- * the variables and functions that still exist in the IR. The symbol
- * table will be used later during linking.
- *
- * There must NOT be any freed objects still referenced by the symbol
- * table. That could cause the linker to dereference freed memory.
- *
- * We don't have to worry about types or interface-types here because those
- * are fly-weights that are looked up by glsl_type.
- */
- foreach_in_list (ir_instruction, ir, shader->ir) {
- switch (ir->ir_type) {
- case ir_type_function:
- shader->symbols->add_function((ir_function *) ir);
- break;
- case ir_type_variable: {
- ir_variable *const var = (ir_variable *) ir;
-
- if (var->data.mode != ir_var_temporary)
- shader->symbols->add_variable(var);
- break;
- }
- default:
- break;
- }
+ if (!state->error && !shader->ir->is_empty()) {
+ if (options->LowerPrecisionFloat16 || options->LowerPrecisionInt16)
+ lower_precision(options, shader->ir);
+ lower_builtins(shader->ir);
+ assign_subroutine_indexes(state);
+ lower_subroutine(shader->ir, state);
+ opt_shader_and_create_symbol_table(ctx, state->symbols, shader);
}
- _mesa_glsl_initialize_derived_variables(ctx, shader);
-
if (!force_recompile) {
free((void *)shader->FallbackSource);
- shader->FallbackSource = NULL;
+
+ /* Copy pre-processed shader include to fallback source otherwise we
+ * have no guarantee the shader include source tree has not changed.
+ */
+ shader->FallbackSource = source_has_shader_include ?
+ strdup(source) : NULL;
}
delete state->symbols;
ralloc_free(state);
+
+ if (ctx->Cache && shader->CompileStatus == COMPILE_SUCCESS) {
+ char sha1_buf[41];
+ disk_cache_put_key(ctx->Cache, shader->sha1);
+ if (ctx->_Shader->Flags & GLSL_CACHE_INFO) {
+ _mesa_sha1_format(sha1_buf, shader->sha1);
+ fprintf(stderr, "marking shader: %s\n", sha1_buf);
+ }
+ }
}
} /* extern "C" */
bool native_integers)
{
const bool debug = false;
- GLboolean progress = GL_FALSE;
+ bool progress = false;
#define OPT(PASS, ...) do { \
if (debug) { \
OPT(do_if_simplification, ir);
OPT(opt_flatten_nested_if_blocks, ir);
OPT(opt_conditional_discard, ir);
- OPT(do_copy_propagation, ir);
OPT(do_copy_propagation_elements, ir);
if (options->OptimizeForAOS && !linked)
options->EmitNoCont, options->EmitNoLoops);
OPT(do_vec_index_to_swizzle, ir);
OPT(lower_vector_insert, ir, false);
- OPT(do_swizzle_swizzle, ir);
- OPT(do_noop_swizzle, ir);
+ OPT(optimize_swizzles, ir);
+
+ /* Some drivers only call do_common_optimization() once rather than in a
+ * loop, and split arrays causes each element of a constant array to
+ * dereference is own copy of the entire array initilizer. This IR is not
+ * something that can be generated manually in a shader and is not
+ * accounted for by NIR optimisations, the result is an exponential slow
+ * down in compilation speed as a constant arrays element count grows. To
+ * avoid that here we make sure to always clean up the mess split arrays
+ * causes to constant arrays.
+ */
+ bool array_split = optimize_split_arrays(ir, linked);
+ if (array_split)
+ do_constant_propagation(ir);
+ progress |= array_split;
- OPT(optimize_split_arrays, ir, linked);
OPT(optimize_redundant_jumps, ir);
if (options->MaxUnrollIterations) {
loop_state *ls = analyze_loop_variables(ir);
if (ls->loop_found) {
- OPT(set_loop_controls, ir, ls);
- OPT(unroll_loops, ir, ls, options);
+ bool loop_progress = unroll_loops(ir, ls, options);
+ while (loop_progress) {
+ loop_progress = false;
+ loop_progress |= do_constant_propagation(ir);
+ loop_progress |= do_if_simplification(ir);
+
+ /* Some drivers only call do_common_optimization() once rather
+ * than in a loop. So we must call do_lower_jumps() after
+ * unrolling a loop because for drivers that use LLVM validation
+ * will fail if a jump is not the last instruction in the block.
+ * For example the following will fail LLVM validation:
+ *
+ * (loop (
+ * ...
+ * break
+ * (assign (x) (var_ref v124) (expression int + (var_ref v124)
+ * (constant int (1)) ) )
+ * ))
+ */
+ loop_progress |= do_lower_jumps(ir, true, true,
+ options->EmitNoMainReturn,
+ options->EmitNoCont,
+ options->EmitNoLoops);
+ }
+ progress |= loop_progress;
}
delete ls;
}
return progress;
}
-
-extern "C" {
-
-/**
- * To be called at GL teardown time, this frees compiler datastructures.
- *
- * After calling this, any previously compiled shaders and shader
- * programs would be invalid. So this should happen at approximately
- * program exit.
- */
-void
-_mesa_destroy_shader_compiler(void)
-{
- _mesa_destroy_shader_compiler_caches();
-
- _mesa_glsl_release_types();
-}
-
-/**
- * Releases compiler caches to trade off performance for memory.
- *
- * Intended to be used with glReleaseShaderCompiler().
- */
-void
-_mesa_destroy_shader_compiler_caches(void)
-{
- _mesa_glsl_release_builtin_functions();
-}
-
-}