* \author Ian Romanick <ian.d.romanick@intel.com>
*/
+#include <ctype.h>
#include "main/core.h"
#include "glsl_symbol_table.h"
#include "glsl_parser_extras.h"
#include "ir_rvalue_visitor.h"
#include "ir_uniform.h"
-extern "C" {
#include "main/shaderobj.h"
#include "main/enums.h"
-}
+
void linker_error(gl_shader_program *, const char *, ...);
emit_vertex.run(prog->_LinkedShaders[MESA_SHADER_GEOMETRY]->ir);
if (emit_vertex.error()) {
linker_error(prog, "Invalid call %s(%d). Accepted values for the "
- "stream parameter are in the range [0, %d].",
+ "stream parameter are in the range [0, %d].\n",
emit_vertex.error_func(),
emit_vertex.error_stream(),
ctx->Const.MaxVertexStreams - 1);
*/
if (prog->Geom.UsesStreams && prog->Geom.OutputType != GL_POINTS) {
linker_error(prog, "EmitStreamVertex(n) and EndStreamPrimitive(n) "
- "with n>0 requires point output");
+ "with n>0 requires point output\n");
+ }
+ }
+}
+
+bool
+validate_intrastage_arrays(struct gl_shader_program *prog,
+ ir_variable *const var,
+ ir_variable *const existing)
+{
+ /* Consider the types to be "the same" if both types are arrays
+ * of the same type and one of the arrays is implicitly sized.
+ * In addition, set the type of the linked variable to the
+ * explicitly sized array.
+ */
+ if (var->type->is_array() && existing->type->is_array() &&
+ (var->type->fields.array == existing->type->fields.array) &&
+ ((var->type->length == 0)|| (existing->type->length == 0))) {
+ if (var->type->length != 0) {
+ if (var->type->length <= existing->data.max_array_access) {
+ linker_error(prog, "%s `%s' declared as type "
+ "`%s' but outermost dimension has an index"
+ " of `%i'\n",
+ mode_string(var),
+ var->name, var->type->name,
+ existing->data.max_array_access);
+ }
+ existing->type = var->type;
+ return true;
+ } else if (existing->type->length != 0) {
+ if(existing->type->length <= var->data.max_array_access) {
+ linker_error(prog, "%s `%s' declared as type "
+ "`%s' but outermost dimension has an index"
+ " of `%i'\n",
+ mode_string(var),
+ var->name, existing->type->name,
+ var->data.max_array_access);
+ }
+ return true;
}
}
+ return false;
}
*/
ir_variable *const existing = variables.get_variable(var->name);
if (existing != NULL) {
- if (var->type != existing->type) {
- /* Consider the types to be "the same" if both types are arrays
- * of the same type and one of the arrays is implicitly sized.
- * In addition, set the type of the linked variable to the
- * explicitly sized array.
- */
- if (var->type->is_array()
- && existing->type->is_array()
- && (var->type->fields.array == existing->type->fields.array)
- && ((var->type->length == 0)
- || (existing->type->length == 0))) {
- if (var->type->length != 0) {
- existing->type = var->type;
- }
- } else if (var->type->is_record()
- && existing->type->is_record()
- && existing->type->record_compare(var->type)) {
- existing->type = var->type;
- } else {
- linker_error(prog, "%s `%s' declared as type "
- "`%s' and type `%s'\n",
- mode_string(var),
- var->name, var->type->name,
- existing->type->name);
- return;
+ /* Check if types match. Interface blocks have some special
+ * rules so we handle those elsewhere.
+ */
+ if (var->type != existing->type &&
+ !var->is_interface_instance()) {
+ if (!validate_intrastage_arrays(prog, var, existing)) {
+ if (var->type->is_record() && existing->type->is_record()
+ && existing->type->record_compare(var->type)) {
+ existing->type = var->type;
+ } else {
+ linker_error(prog, "%s `%s' declared as type "
+ "`%s' and type `%s'\n",
+ mode_string(var),
+ var->name, var->type->name,
+ existing->type->name);
+ return;
+ }
}
}
linker_error(prog,
"All redeclarations of gl_FragDepth in all "
"fragment shaders in a single program must have "
- "the same set of qualifiers.");
+ "the same set of qualifiers.\n");
}
if (var->data.used && layout_differs) {
"qualifier in any fragment shader, it must be "
"redeclared with the same layout qualifier in "
"all fragment shaders that have assignments to "
- "gl_FragDepth");
+ "gl_FragDepth\n");
}
}
&sh->UniformBlocks[j]);
if (index == -1) {
- linker_error(prog, "uniform block `%s' has mismatching definitions",
+ linker_error(prog, "uniform block `%s' has mismatching definitions\n",
sh->UniformBlocks[j].Name);
return false;
}
if ((other_sig != NULL) && other_sig->is_defined
&& !other_sig->is_builtin()) {
- linker_error(prog, "function `%s' is multiply defined",
+ linker_error(prog, "function `%s' is multiply defined\n",
f->name);
return NULL;
}
if (attr + slots > max_index) {
linker_error(prog,
"insufficient contiguous locations "
- "available for %s `%s' %d %d %d", string,
+ "available for %s `%s' %d %d %d\n", string,
var->name, used_locations, use_mask, attr);
return false;
}
linker_error(prog,
"insufficient contiguous locations "
- "available for %s `%s'",
+ "available for %s `%s'\n",
string, to_assign[i].var->name);
return false;
}
continue;
if (sh->num_samplers > ctx->Const.Program[i].MaxTextureImageUnits) {
- linker_error(prog, "Too many %s shader texture samplers",
+ linker_error(prog, "Too many %s shader texture samplers\n",
_mesa_shader_stage_to_string(i));
}
_mesa_shader_stage_to_string(i));
} else {
linker_error(prog, "Too many %s shader default uniform block "
- "components",
+ "components\n",
_mesa_shader_stage_to_string(i));
}
}
"this is non-portable out-of-spec behavior\n",
_mesa_shader_stage_to_string(i));
} else {
- linker_error(prog, "Too many %s shader uniform components",
+ linker_error(prog, "Too many %s shader uniform components\n",
_mesa_shader_stage_to_string(i));
}
}
}
if (total_uniform_blocks > ctx->Const.MaxCombinedUniformBlocks) {
- linker_error(prog, "Too many combined uniform blocks (%d/%d)",
+ linker_error(prog, "Too many combined uniform blocks (%d/%d)\n",
prog->NumUniformBlocks,
ctx->Const.MaxCombinedUniformBlocks);
} else {
const unsigned max_uniform_blocks =
ctx->Const.Program[i].MaxUniformBlocks;
if (blocks[i] > max_uniform_blocks) {
- linker_error(prog, "Too many %s uniform blocks (%d/%d)",
+ linker_error(prog, "Too many %s uniform blocks (%d/%d)\n",
_mesa_shader_stage_to_string(i),
blocks[i],
max_uniform_blocks);
if (sh) {
if (sh->NumImages > ctx->Const.Program[i].MaxImageUniforms)
- linker_error(prog, "Too many %s shader image uniforms",
+ linker_error(prog, "Too many %s shader image uniforms\n",
_mesa_shader_stage_to_string(i));
total_image_units += sh->NumImages;
}
if (total_image_units > ctx->Const.MaxCombinedImageUniforms)
- linker_error(prog, "Too many combined image uniforms");
+ linker_error(prog, "Too many combined image uniforms\n");
if (total_image_units + fragment_outputs >
ctx->Const.MaxCombinedImageUnitsAndFragmentOutputs)
- linker_error(prog, "Too many combined image uniforms and fragment outputs");
+ linker_error(prog, "Too many combined image uniforms and fragment outputs\n");
}
max_loc + 1);
if (!prog->UniformRemapTable) {
- linker_error(prog, "Out of memory during linking.");
+ linker_error(prog, "Out of memory during linking.\n");
return false;
}
*/
linker_error(prog,
"location qualifier for uniform %s overlaps "
- "previously used location",
+ "previously used location\n",
var->name);
return false;
}
string_to_uint_map *uniform_map = new string_to_uint_map;
if (!uniform_map) {
- linker_error(prog, "Out of memory during linking.");
+ linker_error(prog, "Out of memory during linking.\n");
return;
}
*/
if (first == MESA_SHADER_FRAGMENT) {
linker_error(prog, "Transform feedback varyings specified, but "
- "no vertex or geometry shader is present.");
+ "no vertex or geometry shader is present.\n");
goto done;
}
if (last >= 0 && last < MESA_SHADER_FRAGMENT) {
gl_shader *const sh = prog->_LinkedShaders[last];
+ if (first == MESA_SHADER_GEOMETRY) {
+ /* There was no vertex shader, but we still have to assign varying
+ * locations for use by geometry shader inputs in SSO.
+ *
+ * If the shader is not separable (i.e., prog->SeparateShader is
+ * false), linking will have already failed when first is
+ * MESA_SHADER_GEOMETRY.
+ */
+ if (!assign_varying_locations(ctx, mem_ctx, prog,
+ NULL, sh,
+ num_tfeedback_decls, tfeedback_decls,
+ prog->Geom.VerticesIn))
+ goto done;
+ }
+
if (num_tfeedback_decls != 0 || prog->SeparateShader) {
/* There was no fragment shader, but we still have to assign varying
* locations for use by transform feedback.