aboutsummaryrefslogtreecommitdiff
path: root/mesalib/src/glsl
diff options
context:
space:
mode:
authormarha <marha@users.sourceforge.net>2012-07-31 10:17:14 +0200
committermarha <marha@users.sourceforge.net>2012-07-31 10:17:14 +0200
commit83da3ad0287bc51cd16ee6911fe73dc98ebe000b (patch)
tree48d48590a0b0a3770006aeda8ec2b2a45054d1f1 /mesalib/src/glsl
parent00e30605ffc7ac3cf1a091ff2c1f46cfefb780d7 (diff)
parentbd27b3d008b0abf9ae2edcb127302728808533e4 (diff)
downloadvcxsrv-83da3ad0287bc51cd16ee6911fe73dc98ebe000b.tar.gz
vcxsrv-83da3ad0287bc51cd16ee6911fe73dc98ebe000b.tar.bz2
vcxsrv-83da3ad0287bc51cd16ee6911fe73dc98ebe000b.zip
Merge remote-tracking branch 'origin/released'
Diffstat (limited to 'mesalib/src/glsl')
-rw-r--r--mesalib/src/glsl/ast.h6
-rw-r--r--mesalib/src/glsl/ast_to_hir.cpp116
-rw-r--r--mesalib/src/glsl/builtin_types.h5
-rw-r--r--mesalib/src/glsl/glcpp/glcpp-parse.y4
-rw-r--r--mesalib/src/glsl/glsl_parser.yy4
-rw-r--r--mesalib/src/glsl/glsl_parser_extras.cpp16
-rw-r--r--mesalib/src/glsl/glsl_parser_extras.h4
-rw-r--r--mesalib/src/glsl/glsl_types.cpp220
-rw-r--r--mesalib/src/glsl/glsl_types.h18
-rw-r--r--mesalib/src/glsl/ir.cpp1
-rw-r--r--mesalib/src/glsl/ir.h15
-rw-r--r--mesalib/src/glsl/ir_clone.cpp1
-rw-r--r--mesalib/src/glsl/ir_set_program_inouts.cpp36
-rw-r--r--mesalib/src/glsl/ir_uniform.h34
-rw-r--r--mesalib/src/glsl/link_uniforms.cpp177
-rw-r--r--mesalib/src/glsl/linker.cpp91
-rw-r--r--mesalib/src/glsl/linker.h9
-rw-r--r--mesalib/src/glsl/lower_vector.cpp2
-rw-r--r--mesalib/src/glsl/opt_dead_code.cpp8
-rw-r--r--mesalib/src/glsl/strtod.c2
20 files changed, 725 insertions, 44 deletions
diff --git a/mesalib/src/glsl/ast.h b/mesalib/src/glsl/ast.h
index 6d81afc99..3c0a2b838 100644
--- a/mesalib/src/glsl/ast.h
+++ b/mesalib/src/glsl/ast.h
@@ -517,6 +517,12 @@ public:
* is used to note these cases when no type is specified.
*/
int invariant;
+
+ /**
+ * Flag indicating that these declarators are in a uniform block,
+ * allowing UBO type qualifiers.
+ */
+ bool ubo_qualifiers_valid;
};
diff --git a/mesalib/src/glsl/ast_to_hir.cpp b/mesalib/src/glsl/ast_to_hir.cpp
index bbe8f0596..1c54991cf 100644
--- a/mesalib/src/glsl/ast_to_hir.cpp
+++ b/mesalib/src/glsl/ast_to_hir.cpp
@@ -1917,7 +1917,8 @@ static void
apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual,
ir_variable *var,
struct _mesa_glsl_parse_state *state,
- YYLTYPE *loc)
+ YYLTYPE *loc,
+ bool ubo_qualifiers_valid)
{
if (qual->flags.q.invariant) {
if (var->used) {
@@ -2010,24 +2011,10 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual,
if (var->interpolation != INTERP_QUALIFIER_NONE &&
!(state->target == vertex_shader && var->mode == ir_var_out) &&
!(state->target == fragment_shader && var->mode == ir_var_in)) {
- const char *qual_string = NULL;
- switch (var->interpolation) {
- case INTERP_QUALIFIER_FLAT:
- qual_string = "flat";
- break;
- case INTERP_QUALIFIER_NOPERSPECTIVE:
- qual_string = "noperspective";
- break;
- case INTERP_QUALIFIER_SMOOTH:
- qual_string = "smooth";
- break;
- }
-
_mesa_glsl_error(loc, state,
"interpolation qualifier `%s' can only be applied to "
"vertex shader outputs and fragment shader inputs.",
- qual_string);
-
+ var->interpolation_string());
}
var->pixel_center_integer = qual->flags.q.pixel_center_integer;
@@ -2191,6 +2178,23 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual,
var->depth_layout = ir_depth_layout_unchanged;
else
var->depth_layout = ir_depth_layout_none;
+
+ if (qual->flags.q.std140 ||
+ qual->flags.q.packed ||
+ qual->flags.q.shared) {
+ _mesa_glsl_error(loc, state,
+ "uniform block layout qualifiers std140, packed, and "
+ "shared can only be applied to uniform blocks, not "
+ "members");
+ }
+
+ if (!ubo_qualifiers_valid &&
+ (qual->flags.q.row_major || qual->flags.q.column_major)) {
+ _mesa_glsl_error(loc, state,
+ "uniform block layout qualifiers row_major and "
+ "column_major can only be applied to uniform block "
+ "members");
+ }
}
/**
@@ -2611,7 +2615,7 @@ ast_declarator_list::hir(exec_list *instructions,
}
apply_type_qualifier_to_variable(& this->type->qualifier, var, state,
- & loc);
+ & loc, this->ubo_qualifiers_valid);
if (this->type->qualifier.flags.q.invariant) {
if ((state->target == vertex_shader) && !(var->mode == ir_var_out ||
@@ -3028,7 +3032,8 @@ ast_parameter_declarator::hir(exec_list *instructions,
/* Apply any specified qualifiers to the parameter declaration. Note that
* for function parameters the default mode is 'in'.
*/
- apply_type_qualifier_to_variable(& this->type->qualifier, var, state, & loc);
+ apply_type_qualifier_to_variable(& this->type->qualifier, var, state, & loc,
+ false);
/* From page 17 (page 23 of the PDF) of the GLSL 1.20 spec:
*
@@ -3989,6 +3994,25 @@ ast_struct_specifier::hir(exec_list *instructions,
return NULL;
}
+static struct gl_uniform_block *
+get_next_uniform_block(struct _mesa_glsl_parse_state *state)
+{
+ if (state->num_uniform_blocks >= state->uniform_block_array_size) {
+ state->uniform_block_array_size *= 2;
+ if (state->uniform_block_array_size <= 4)
+ state->uniform_block_array_size = 4;
+
+ state->uniform_blocks = reralloc(state,
+ state->uniform_blocks,
+ struct gl_uniform_block,
+ state->uniform_block_array_size);
+ }
+
+ memset(&state->uniform_blocks[state->num_uniform_blocks],
+ 0, sizeof(*state->uniform_blocks));
+ return &state->uniform_blocks[state->num_uniform_blocks++];
+}
+
ir_rvalue *
ast_uniform_block::hir(exec_list *instructions,
struct _mesa_glsl_parse_state *state)
@@ -3997,6 +4021,62 @@ ast_uniform_block::hir(exec_list *instructions,
* need to turn those into ir_variables with an association
* with this uniform block.
*/
+ struct gl_uniform_block *ubo = get_next_uniform_block(state);
+ ubo->Name = ralloc_strdup(state->uniform_blocks, this->block_name);
+
+ unsigned int num_variables = 0;
+ foreach_list_typed(ast_declarator_list, decl_list, link, &declarations) {
+ foreach_list_const(node, &decl_list->declarations) {
+ num_variables++;
+ }
+ }
+
+ bool block_row_major = this->layout.flags.q.row_major;
+
+ ubo->Uniforms = rzalloc_array(state->uniform_blocks,
+ struct gl_uniform_buffer_variable,
+ num_variables);
+
+ foreach_list_typed(ast_declarator_list, decl_list, link, &declarations) {
+ exec_list declared_variables;
+
+ decl_list->hir(&declared_variables, state);
+
+ foreach_list_const(node, &declared_variables) {
+ struct ir_variable *var = (ir_variable *)node;
+
+ struct gl_uniform_buffer_variable *ubo_var =
+ &ubo->Uniforms[ubo->NumUniforms++];
+
+ var->uniform_block = ubo - state->uniform_blocks;
+
+ ubo_var->Name = ralloc_strdup(state->uniform_blocks, var->name);
+ ubo_var->Type = var->type;
+ ubo_var->Buffer = ubo - state->uniform_blocks;
+ ubo_var->Offset = 0; /* Assigned at link time. */
+ ubo_var->RowMajor = block_row_major;
+ if (decl_list->type->qualifier.flags.q.row_major)
+ ubo_var->RowMajor = true;
+ else if (decl_list->type->qualifier.flags.q.column_major)
+ ubo_var->RowMajor = false;
+
+ /* From the GL_ARB_uniform_buffer_object spec:
+ *
+ * "Sampler types are not allowed inside of uniform
+ * blocks. All other types, arrays, and structures
+ * allowed for uniforms are allowed within a uniform
+ * block."
+ */
+ if (var->type->contains_sampler()) {
+ YYLTYPE loc = decl_list->get_location();
+ _mesa_glsl_error(&loc, state,
+ "Uniform in non-default uniform block contains sampler\n");
+ }
+ }
+
+ instructions->append_list(&declared_variables);
+ }
+
return NULL;
}
diff --git a/mesalib/src/glsl/builtin_types.h b/mesalib/src/glsl/builtin_types.h
index 8c136e4ab..d75c56261 100644
--- a/mesalib/src/glsl/builtin_types.h
+++ b/mesalib/src/glsl/builtin_types.h
@@ -63,7 +63,12 @@ const glsl_type glsl_type::builtin_core_types[] = {
};
const glsl_type *const glsl_type::bool_type = & builtin_core_types[0];
+const glsl_type *const glsl_type::bvec2_type = & builtin_core_types[1];
+const glsl_type *const glsl_type::bvec3_type = & builtin_core_types[2];
+const glsl_type *const glsl_type::bvec4_type = & builtin_core_types[3];
const glsl_type *const glsl_type::int_type = & builtin_core_types[4];
+const glsl_type *const glsl_type::ivec2_type = & builtin_core_types[5];
+const glsl_type *const glsl_type::ivec3_type = & builtin_core_types[6];
const glsl_type *const glsl_type::ivec4_type = & builtin_core_types[7];
const glsl_type *const glsl_type::float_type = & builtin_core_types[8];
const glsl_type *const glsl_type::vec2_type = & builtin_core_types[9];
diff --git a/mesalib/src/glsl/glcpp/glcpp-parse.y b/mesalib/src/glsl/glcpp/glcpp-parse.y
index c0c1ca197..bf6f3ad01 100644
--- a/mesalib/src/glsl/glcpp/glcpp-parse.y
+++ b/mesalib/src/glsl/glcpp/glcpp-parse.y
@@ -213,7 +213,7 @@ expanded_line:
parser->new_line_number = $2;
ralloc_asprintf_rewrite_tail (&parser->output,
&parser->output_length,
- "#line %" PRIiMAX,
+ "#line %" PRIiMAX "\n",
$2);
}
| LINE_EXPANDED integer_constant integer_constant NEWLINE {
@@ -223,7 +223,7 @@ expanded_line:
parser->new_source_number = $3;
ralloc_asprintf_rewrite_tail (&parser->output,
&parser->output_length,
- "#line %" PRIiMAX " %" PRIiMAX,
+ "#line %" PRIiMAX " %" PRIiMAX "\n",
$2, $3);
}
;
diff --git a/mesalib/src/glsl/glsl_parser.yy b/mesalib/src/glsl/glsl_parser.yy
index 337337591..f61d6b8dd 100644
--- a/mesalib/src/glsl/glsl_parser.yy
+++ b/mesalib/src/glsl/glsl_parser.yy
@@ -301,7 +301,7 @@ pragma_statement:
| PRAGMA_OPTIMIZE_OFF EOL
| PRAGMA_INVARIANT_ALL EOL
{
- if (state->language_version < 120) {
+ if (state->language_version < 120 && !state->Const.GLSL_100ES) {
_mesa_glsl_warning(& @1, state,
"pragma `invariant(all)' not supported in %s",
state->version_string);
@@ -1967,6 +1967,7 @@ member_declaration:
type->specifier = $3;
$$ = new(ctx) ast_declarator_list(type);
$$->set_location(yylloc);
+ $$->ubo_qualifiers_valid = true;
$$->declarations.push_degenerate_list_at_head(& $4->link);
}
@@ -1980,6 +1981,7 @@ member_declaration:
type->specifier = $2;
$$ = new(ctx) ast_declarator_list(type);
$$->set_location(yylloc);
+ $$->ubo_qualifiers_valid = true;
$$->declarations.push_degenerate_list_at_head(& $3->link);
}
diff --git a/mesalib/src/glsl/glsl_parser_extras.cpp b/mesalib/src/glsl/glsl_parser_extras.cpp
index d9ee406cf..7a9b22197 100644
--- a/mesalib/src/glsl/glsl_parser_extras.cpp
+++ b/mesalib/src/glsl/glsl_parser_extras.cpp
@@ -27,6 +27,7 @@
extern "C" {
#include "main/core.h" /* for struct gl_context */
+#include "main/context.h"
}
#include "ralloc.h"
@@ -90,19 +91,17 @@ _mesa_glsl_parse_state::_mesa_glsl_parse_state(struct gl_context *_ctx,
*/
this->Const.GLSL_100ES = (ctx->API == API_OPENGLES2)
|| ctx->Extensions.ARB_ES2_compatibility;
- this->Const.GLSL_110 = (ctx->API == API_OPENGL);
- this->Const.GLSL_120 = (ctx->API == API_OPENGL)
- && (ctx->Const.GLSLVersion >= 120);
- this->Const.GLSL_130 = (ctx->API == API_OPENGL)
- && (ctx->Const.GLSLVersion >= 130);
- this->Const.GLSL_140 = (ctx->API == API_OPENGL)
- && (ctx->Const.GLSLVersion >= 140);
+ bool is_desktop_gl = _mesa_is_desktop_gl(ctx);
+ this->Const.GLSL_110 = is_desktop_gl;
+ this->Const.GLSL_120 = is_desktop_gl && (ctx->Const.GLSLVersion >= 120);
+ this->Const.GLSL_130 = is_desktop_gl && (ctx->Const.GLSLVersion >= 130);
+ this->Const.GLSL_140 = is_desktop_gl && (ctx->Const.GLSLVersion >= 140);
const unsigned lowest_version =
(ctx->API == API_OPENGLES2) || ctx->Extensions.ARB_ES2_compatibility
? 100 : 110;
const unsigned highest_version =
- (ctx->API == API_OPENGL) ? ctx->Const.GLSLVersion : 100;
+ is_desktop_gl ? ctx->Const.GLSLVersion : 100;
char *supported = ralloc_strdup(this, "");
for (unsigned ver = lowest_version; ver <= highest_version; ver += 10) {
@@ -773,6 +772,7 @@ ast_declarator_list::ast_declarator_list(ast_fully_specified_type *type)
{
this->type = type;
this->invariant = false;
+ this->ubo_qualifiers_valid = false;
}
void
diff --git a/mesalib/src/glsl/glsl_parser_extras.h b/mesalib/src/glsl/glsl_parser_extras.h
index 2564e5856..cf6dfbe3b 100644
--- a/mesalib/src/glsl/glsl_parser_extras.h
+++ b/mesalib/src/glsl/glsl_parser_extras.h
@@ -86,6 +86,10 @@ struct _mesa_glsl_parse_state {
exec_list translation_unit;
glsl_symbol_table *symbols;
+ unsigned num_uniform_blocks;
+ unsigned uniform_block_array_size;
+ struct gl_uniform_block *uniform_blocks;
+
bool es_shader;
unsigned language_version;
const char *version_string;
diff --git a/mesalib/src/glsl/glsl_types.cpp b/mesalib/src/glsl/glsl_types.cpp
index 8a34b8eb0..3d7866058 100644
--- a/mesalib/src/glsl/glsl_types.cpp
+++ b/mesalib/src/glsl/glsl_types.cpp
@@ -628,3 +628,223 @@ glsl_type::can_implicitly_convert_to(const glsl_type *desired) const
&& this->is_integer()
&& this->vector_elements == desired->vector_elements;
}
+
+unsigned
+glsl_type::std140_base_alignment(bool row_major) const
+{
+ /* (1) If the member is a scalar consuming <N> basic machine units, the
+ * base alignment is <N>.
+ *
+ * (2) If the member is a two- or four-component vector with components
+ * consuming <N> basic machine units, the base alignment is 2<N> or
+ * 4<N>, respectively.
+ *
+ * (3) If the member is a three-component vector with components consuming
+ * <N> basic machine units, the base alignment is 4<N>.
+ */
+ if (this->is_scalar() || this->is_vector()) {
+ switch (this->vector_elements) {
+ case 1:
+ return 4;
+ case 2:
+ return 8;
+ case 3:
+ case 4:
+ return 16;
+ }
+ }
+
+ /* (4) If the member is an array of scalars or vectors, the base alignment
+ * and array stride are set to match the base alignment of a single
+ * array element, according to rules (1), (2), and (3), and rounded up
+ * to the base alignment of a vec4. The array may have padding at the
+ * end; the base offset of the member following the array is rounded up
+ * to the next multiple of the base alignment.
+ *
+ * (6) If the member is an array of <S> column-major matrices with <C>
+ * columns and <R> rows, the matrix is stored identically to a row of
+ * <S>*<C> column vectors with <R> components each, according to rule
+ * (4).
+ *
+ * (8) If the member is an array of <S> row-major matrices with <C> columns
+ * and <R> rows, the matrix is stored identically to a row of <S>*<R>
+ * row vectors with <C> components each, according to rule (4).
+ *
+ * (10) If the member is an array of <S> structures, the <S> elements of
+ * the array are laid out in order, according to rule (9).
+ */
+ if (this->is_array()) {
+ if (this->fields.array->is_scalar() ||
+ this->fields.array->is_vector() ||
+ this->fields.array->is_matrix()) {
+ return MAX2(this->fields.array->std140_base_alignment(row_major), 16);
+ } else {
+ assert(this->fields.array->is_record());
+ return this->fields.array->std140_base_alignment(row_major);
+ }
+ }
+
+ /* (5) If the member is a column-major matrix with <C> columns and
+ * <R> rows, the matrix is stored identically to an array of
+ * <C> column vectors with <R> components each, according to
+ * rule (4).
+ *
+ * (7) If the member is a row-major matrix with <C> columns and <R>
+ * rows, the matrix is stored identically to an array of <R>
+ * row vectors with <C> components each, according to rule (4).
+ */
+ if (this->is_matrix()) {
+ const struct glsl_type *vec_type;
+ if (row_major) {
+ vec_type = get_instance(GLSL_TYPE_FLOAT, this->vector_elements, 1);
+ } else {
+ vec_type = get_instance(GLSL_TYPE_FLOAT, this->matrix_columns, 1);
+ }
+
+ return vec_type->std140_base_alignment(false);
+ }
+
+ /* (9) If the member is a structure, the base alignment of the
+ * structure is <N>, where <N> is the largest base alignment
+ * value of any of its members, and rounded up to the base
+ * alignment of a vec4. The individual members of this
+ * sub-structure are then assigned offsets by applying this set
+ * of rules recursively, where the base offset of the first
+ * member of the sub-structure is equal to the aligned offset
+ * of the structure. The structure may have padding at the end;
+ * the base offset of the member following the sub-structure is
+ * rounded up to the next multiple of the base alignment of the
+ * structure.
+ */
+ if (this->is_record()) {
+ unsigned base_alignment = 16;
+ for (unsigned i = 0; i < this->length; i++) {
+ const struct glsl_type *field_type = this->fields.structure[i].type;
+ base_alignment = MAX2(base_alignment,
+ field_type->std140_base_alignment(row_major));
+ }
+ return base_alignment;
+ }
+
+ assert(!"not reached");
+ return -1;
+}
+
+static unsigned
+align(unsigned val, unsigned align)
+{
+ return (val + align - 1) / align * align;
+}
+
+unsigned
+glsl_type::std140_size(bool row_major) const
+{
+ /* (1) If the member is a scalar consuming <N> basic machine units, the
+ * base alignment is <N>.
+ *
+ * (2) If the member is a two- or four-component vector with components
+ * consuming <N> basic machine units, the base alignment is 2<N> or
+ * 4<N>, respectively.
+ *
+ * (3) If the member is a three-component vector with components consuming
+ * <N> basic machine units, the base alignment is 4<N>.
+ */
+ if (this->is_scalar() || this->is_vector()) {
+ return this->vector_elements * 4;
+ }
+
+ /* (5) If the member is a column-major matrix with <C> columns and
+ * <R> rows, the matrix is stored identically to an array of
+ * <C> column vectors with <R> components each, according to
+ * rule (4).
+ *
+ * (6) If the member is an array of <S> column-major matrices with <C>
+ * columns and <R> rows, the matrix is stored identically to a row of
+ * <S>*<C> column vectors with <R> components each, according to rule
+ * (4).
+ *
+ * (7) If the member is a row-major matrix with <C> columns and <R>
+ * rows, the matrix is stored identically to an array of <R>
+ * row vectors with <C> components each, according to rule (4).
+ *
+ * (8) If the member is an array of <S> row-major matrices with <C> columns
+ * and <R> rows, the matrix is stored identically to a row of <S>*<R>
+ * row vectors with <C> components each, according to rule (4).
+ */
+ if (this->is_matrix() || (this->is_array() &&
+ this->fields.array->is_matrix())) {
+ const struct glsl_type *element_type;
+ const struct glsl_type *vec_type;
+ unsigned int array_len;
+
+ if (this->is_array()) {
+ element_type = this->fields.array;
+ array_len = this->length;
+ } else {
+ element_type = this;
+ array_len = 1;
+ }
+
+ if (row_major) {
+ vec_type = get_instance(GLSL_TYPE_FLOAT,
+ element_type->matrix_columns, 1);
+ array_len *= element_type->vector_elements;
+ } else {
+ vec_type = get_instance(GLSL_TYPE_FLOAT,
+ element_type->vector_elements, 1);
+ array_len *= element_type->matrix_columns;
+ }
+ const glsl_type *array_type = glsl_type::get_array_instance(vec_type,
+ array_len);
+
+ return array_type->std140_size(false);
+ }
+
+ /* (4) If the member is an array of scalars or vectors, the base alignment
+ * and array stride are set to match the base alignment of a single
+ * array element, according to rules (1), (2), and (3), and rounded up
+ * to the base alignment of a vec4. The array may have padding at the
+ * end; the base offset of the member following the array is rounded up
+ * to the next multiple of the base alignment.
+ *
+ * (10) If the member is an array of <S> structures, the <S> elements of
+ * the array are laid out in order, according to rule (9).
+ */
+ if (this->is_array()) {
+ if (this->fields.array->is_record()) {
+ return this->length * this->fields.array->std140_size(row_major);
+ } else {
+ unsigned element_base_align =
+ this->fields.array->std140_base_alignment(row_major);
+ return this->length * MAX2(element_base_align, 16);
+ }
+ }
+
+ /* (9) If the member is a structure, the base alignment of the
+ * structure is <N>, where <N> is the largest base alignment
+ * value of any of its members, and rounded up to the base
+ * alignment of a vec4. The individual members of this
+ * sub-structure are then assigned offsets by applying this set
+ * of rules recursively, where the base offset of the first
+ * member of the sub-structure is equal to the aligned offset
+ * of the structure. The structure may have padding at the end;
+ * the base offset of the member following the sub-structure is
+ * rounded up to the next multiple of the base alignment of the
+ * structure.
+ */
+ if (this->is_record()) {
+ unsigned size = 0;
+ for (unsigned i = 0; i < this->length; i++) {
+ const struct glsl_type *field_type = this->fields.structure[i].type;
+ unsigned align = field_type->std140_base_alignment(row_major);
+ size = (size + align - 1) / align * align;
+ size += field_type->std140_size(row_major);
+ }
+ size = align(size,
+ this->fields.structure[0].type->std140_base_alignment(row_major));
+ return size;
+ }
+
+ assert(!"not reached");
+ return -1;
+}
diff --git a/mesalib/src/glsl/glsl_types.h b/mesalib/src/glsl/glsl_types.h
index 48d41d7f8..915d1a22b 100644
--- a/mesalib/src/glsl/glsl_types.h
+++ b/mesalib/src/glsl/glsl_types.h
@@ -152,6 +152,8 @@ struct glsl_type {
static const glsl_type *const error_type;
static const glsl_type *const void_type;
static const glsl_type *const int_type;
+ static const glsl_type *const ivec2_type;
+ static const glsl_type *const ivec3_type;
static const glsl_type *const ivec4_type;
static const glsl_type *const uint_type;
static const glsl_type *const uvec2_type;
@@ -162,6 +164,9 @@ struct glsl_type {
static const glsl_type *const vec3_type;
static const glsl_type *const vec4_type;
static const glsl_type *const bool_type;
+ static const glsl_type *const bvec2_type;
+ static const glsl_type *const bvec3_type;
+ static const glsl_type *const bvec4_type;
static const glsl_type *const mat2_type;
static const glsl_type *const mat2x3_type;
static const glsl_type *const mat2x4_type;
@@ -243,6 +248,19 @@ struct glsl_type {
unsigned component_slots() const;
/**
+ * Alignment in bytes of the start of this type in a std140 uniform
+ * block.
+ */
+ unsigned std140_base_alignment(bool row_major) const;
+
+ /** Size in bytes of this type in a std140 uniform block.
+ *
+ * Note that this is not GL_UNIFORM_SIZE (which is the number of
+ * elements in the array)
+ */
+ unsigned std140_size(bool row_major) const;
+
+ /**
* \brief Can this type be implicitly converted to another?
*
* \return True if the types are identical or if this type can be converted
diff --git a/mesalib/src/glsl/ir.cpp b/mesalib/src/glsl/ir.cpp
index 1c9eec6e2..b0e38d820 100644
--- a/mesalib/src/glsl/ir.cpp
+++ b/mesalib/src/glsl/ir.cpp
@@ -1491,6 +1491,7 @@ ir_variable::ir_variable(const struct glsl_type *type, const char *name,
this->explicit_location = false;
this->has_initializer = false;
this->location = -1;
+ this->uniform_block = -1;
this->warn_extension = NULL;
this->constant_value = NULL;
this->constant_initializer = NULL;
diff --git a/mesalib/src/glsl/ir.h b/mesalib/src/glsl/ir.h
index 9bbf3b7ef..f019837d5 100644
--- a/mesalib/src/glsl/ir.h
+++ b/mesalib/src/glsl/ir.h
@@ -453,7 +453,8 @@ public:
* - Vertex shader output: one of the values from \c gl_vert_result.
* - Fragment shader input: one of the values from \c gl_frag_attrib.
* - Fragment shader output: one of the values from \c gl_frag_result.
- * - Uniforms: Per-stage uniform slot number.
+ * - Uniforms: Per-stage uniform slot number for default uniform block.
+ * - Uniforms: Index within the uniform block definition for UBO members.
* - Other: This field is not currently used.
*
* If the variable is a uniform, shader input, or shader output, and the
@@ -462,6 +463,16 @@ public:
int location;
/**
+ * Uniform block number for uniforms.
+ *
+ * This index is into the shader's list of uniform blocks, not the
+ * linked program's merged list.
+ *
+ * If the variable is not in a uniform block, the value will be -1.
+ */
+ int uniform_block;
+
+ /**
* output index for dual source blending.
*/
int index;
@@ -1016,7 +1027,7 @@ enum ir_expression_operation {
/**
* A sentinel marking the last of all operations.
*/
- ir_last_opcode = ir_last_binop
+ ir_last_opcode = ir_quadop_vector
};
class ir_expression : public ir_rvalue {
diff --git a/mesalib/src/glsl/ir_clone.cpp b/mesalib/src/glsl/ir_clone.cpp
index 591fe7b77..4314efa76 100644
--- a/mesalib/src/glsl/ir_clone.cpp
+++ b/mesalib/src/glsl/ir_clone.cpp
@@ -54,6 +54,7 @@ ir_variable::clone(void *mem_ctx, struct hash_table *ht) const
var->interpolation = this->interpolation;
var->location = this->location;
var->index = this->index;
+ var->uniform_block = this->uniform_block;
var->warn_extension = this->warn_extension;
var->origin_upper_left = this->origin_upper_left;
var->pixel_center_integer = this->pixel_center_integer;
diff --git a/mesalib/src/glsl/ir_set_program_inouts.cpp b/mesalib/src/glsl/ir_set_program_inouts.cpp
index a7415c7e3..e5de07e01 100644
--- a/mesalib/src/glsl/ir_set_program_inouts.cpp
+++ b/mesalib/src/glsl/ir_set_program_inouts.cpp
@@ -26,8 +26,8 @@
*
* Sets the InputsRead and OutputsWritten of Mesa programs.
*
- * Additionally, for fragment shaders, sets the InterpQualifier array and
- * IsCentroid bitfield.
+ * Additionally, for fragment shaders, sets the InterpQualifier array, the
+ * IsCentroid bitfield, and the UsesDFdy flag.
*
* Mesa programs (gl_program, not gl_shader_program) have a set of
* flags indicating which varyings are read and written. Computing
@@ -61,6 +61,8 @@ public:
virtual ir_visitor_status visit_enter(ir_dereference_array *);
virtual ir_visitor_status visit_enter(ir_function_signature *);
+ virtual ir_visitor_status visit_enter(ir_expression *);
+ virtual ir_visitor_status visit_enter(ir_discard *);
virtual ir_visitor_status visit(ir_dereference_variable *);
virtual ir_visitor_status visit(ir_variable *);
@@ -169,6 +171,28 @@ ir_set_program_inouts_visitor::visit_enter(ir_function_signature *ir)
return visit_continue_with_parent;
}
+ir_visitor_status
+ir_set_program_inouts_visitor::visit_enter(ir_expression *ir)
+{
+ if (is_fragment_shader && ir->operation == ir_unop_dFdy) {
+ gl_fragment_program *fprog = (gl_fragment_program *) prog;
+ fprog->UsesDFdy = true;
+ }
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_set_program_inouts_visitor::visit_enter(ir_discard *)
+{
+ /* discards are only allowed in fragment shaders. */
+ assert(is_fragment_shader);
+
+ gl_fragment_program *fprog = (gl_fragment_program *) prog;
+ fprog->UsesKill = true;
+
+ return visit_continue;
+}
+
void
do_set_program_inouts(exec_list *instructions, struct gl_program *prog,
bool is_fragment_shader)
@@ -179,9 +203,11 @@ do_set_program_inouts(exec_list *instructions, struct gl_program *prog,
prog->OutputsWritten = 0;
prog->SystemValuesRead = 0;
if (is_fragment_shader) {
- memset(((gl_fragment_program *) prog)->InterpQualifier, 0,
- sizeof(((gl_fragment_program *) prog)->InterpQualifier));
- ((gl_fragment_program *) prog)->IsCentroid = 0;
+ gl_fragment_program *fprog = (gl_fragment_program *) prog;
+ memset(fprog->InterpQualifier, 0, sizeof(fprog->InterpQualifier));
+ fprog->IsCentroid = 0;
+ fprog->UsesDFdy = false;
+ fprog->UsesKill = false;
}
visit_list_elements(&v, instructions);
}
diff --git a/mesalib/src/glsl/ir_uniform.h b/mesalib/src/glsl/ir_uniform.h
index 225da3fc5..913c53773 100644
--- a/mesalib/src/glsl/ir_uniform.h
+++ b/mesalib/src/glsl/ir_uniform.h
@@ -119,6 +119,40 @@ struct gl_uniform_storage {
* uniform if the \c ::driver_storage interface is not used.
*/
union gl_constant_value *storage;
+
+ /** Fields for GL_ARB_uniform_buffer_object
+ * @{
+ */
+
+ /**
+ * GL_UNIFORM_BLOCK_INDEX: index of the uniform block containing
+ * the uniform, or -1 for the default uniform block. Note that the
+ * index is into the linked program's UniformBlocks[] array, not
+ * the linked shader's.
+ */
+ int block_index;
+
+ /** GL_UNIFORM_OFFSET: byte offset within the uniform block, or -1. */
+ int offset;
+
+ /**
+ * GL_UNIFORM_MATRIX_STRIDE: byte stride between columns or rows of
+ * a matrix. Set to 0 for non-matrices in UBOs, or -1 for uniforms
+ * in the default uniform block.
+ */
+ int matrix_stride;
+
+ /**
+ * GL_UNIFORM_ARRAY_STRIDE: byte stride between elements of the
+ * array. Set to zero for non-arrays in UBOs, or -1 for uniforms
+ * in the default uniform block.
+ */
+ int array_stride;
+
+ /** GL_UNIFORM_ROW_MAJOR: true iff it's a row-major matrix in a UBO */
+ bool row_major;
+
+ /** @} */
};
#ifdef __cplusplus
diff --git a/mesalib/src/glsl/link_uniforms.cpp b/mesalib/src/glsl/link_uniforms.cpp
index 3cbc50510..307f5de09 100644
--- a/mesalib/src/glsl/link_uniforms.cpp
+++ b/mesalib/src/glsl/link_uniforms.cpp
@@ -27,6 +27,13 @@
#include "ir_uniform.h"
#include "glsl_symbol_table.h"
#include "program/hash_table.h"
+#include "program.h"
+
+static inline unsigned int
+align(unsigned int a, unsigned int align)
+{
+ return (a + align - 1) / align * align;
+}
/**
* \file link_uniforms.cpp
@@ -216,6 +223,28 @@ public:
this->shader_shadow_samplers = 0;
}
+ void set_and_process(struct gl_shader_program *prog,
+ ir_variable *var)
+ {
+ ubo_var = NULL;
+ if (var->uniform_block != -1) {
+ struct gl_uniform_block *block =
+ &prog->UniformBlocks[var->uniform_block];
+
+ ubo_block_index = var->uniform_block;
+ ubo_var_index = var->location;
+ ubo_var = &block->Uniforms[var->location];
+ ubo_byte_offset = ubo_var->Offset;
+ }
+
+ process(var);
+ }
+
+ struct gl_uniform_buffer_variable *ubo_var;
+ int ubo_block_index;
+ int ubo_var_index;
+ int ubo_byte_offset;
+
private:
virtual void visit_field(const glsl_type *type, const char *name)
{
@@ -291,6 +320,25 @@ private:
this->uniforms[id].num_driver_storage = 0;
this->uniforms[id].driver_storage = NULL;
this->uniforms[id].storage = this->values;
+ if (this->ubo_var) {
+ this->uniforms[id].block_index = this->ubo_block_index;
+
+ unsigned alignment = type->std140_base_alignment(ubo_var->RowMajor);
+ this->ubo_byte_offset = align(this->ubo_byte_offset, alignment);
+ this->uniforms[id].offset = this->ubo_byte_offset;
+ this->ubo_byte_offset += type->std140_size(ubo_var->RowMajor);
+
+ this->uniforms[id].array_stride = 0;
+ this->uniforms[id].matrix_stride = 0;
+ this->uniforms[id].row_major = base_type->is_matrix() &&
+ ubo_var->RowMajor;
+ } else {
+ this->uniforms[id].block_index = -1;
+ this->uniforms[id].offset = -1;
+ this->uniforms[id].array_stride = -1;
+ this->uniforms[id].matrix_stride = -1;
+ this->uniforms[id].row_major = false;
+ }
this->values += values_for_type(type);
}
@@ -316,6 +364,125 @@ public:
unsigned shader_shadow_samplers;
};
+/**
+ * Merges a uniform block into an array of uniform blocks that may or
+ * may not already contain a copy of it.
+ *
+ * Returns the index of the new block in the array.
+ */
+int
+link_cross_validate_uniform_block(void *mem_ctx,
+ struct gl_uniform_block **linked_blocks,
+ unsigned int *num_linked_blocks,
+ struct gl_uniform_block *new_block)
+{
+ for (unsigned int i = 0; i < *num_linked_blocks; i++) {
+ struct gl_uniform_block *old_block = &(*linked_blocks)[i];
+ if (strcmp(old_block->Name, new_block->Name) == 0) {
+ if (old_block->NumUniforms != new_block->NumUniforms) {
+ return -1;
+ }
+
+ for (unsigned j = 0; j < old_block->NumUniforms; j++) {
+ if (strcmp(old_block->Uniforms[j].Name,
+ new_block->Uniforms[j].Name) != 0)
+ return -1;
+
+ if (old_block->Uniforms[j].Offset !=
+ new_block->Uniforms[j].Offset)
+ return -1;
+
+ if (old_block->Uniforms[j].RowMajor !=
+ new_block->Uniforms[j].RowMajor)
+ return -1;
+ }
+ return i;
+ }
+ }
+
+ *linked_blocks = reralloc(mem_ctx, *linked_blocks,
+ struct gl_uniform_block,
+ *num_linked_blocks + 1);
+ int linked_block_index = (*num_linked_blocks)++;
+ struct gl_uniform_block *linked_block = &(*linked_blocks)[linked_block_index];
+
+ memcpy(linked_block, new_block, sizeof(*new_block));
+ linked_block->Uniforms = ralloc_array(*linked_blocks,
+ struct gl_uniform_buffer_variable,
+ linked_block->NumUniforms);
+
+ memcpy(linked_block->Uniforms,
+ new_block->Uniforms,
+ sizeof(*linked_block->Uniforms) * linked_block->NumUniforms);
+
+ for (unsigned int i = 0; i < linked_block->NumUniforms; i++) {
+ struct gl_uniform_buffer_variable *ubo_var =
+ &linked_block->Uniforms[i];
+
+ ubo_var->Name = ralloc_strdup(*linked_blocks, ubo_var->Name);
+ }
+
+ return linked_block_index;
+}
+
+/**
+ * Walks the IR and update the references to uniform blocks in the
+ * ir_variables to point at linked shader's list (previously, they
+ * would point at the uniform block list in one of the pre-linked
+ * shaders).
+ */
+static bool
+link_update_uniform_buffer_variables(struct gl_shader *shader)
+{
+ foreach_list(node, shader->ir) {
+ ir_variable *const var = ((ir_instruction *) node)->as_variable();
+
+ if ((var == NULL) || (var->uniform_block == -1))
+ continue;
+
+ assert(var->mode == ir_var_uniform);
+
+ bool found = false;
+ for (unsigned i = 0; i < shader->NumUniformBlocks; i++) {
+ for (unsigned j = 0; j < shader->UniformBlocks[i].NumUniforms; j++) {
+ if (!strcmp(var->name, shader->UniformBlocks[i].Uniforms[j].Name)) {
+ found = true;
+ var->uniform_block = i;
+ var->location = j;
+ break;
+ }
+ }
+ if (found)
+ break;
+ }
+ assert(found);
+ }
+
+ return true;
+}
+
+void
+link_assign_uniform_block_offsets(struct gl_shader *shader)
+{
+ for (unsigned b = 0; b < shader->NumUniformBlocks; b++) {
+ struct gl_uniform_block *block = &shader->UniformBlocks[b];
+
+ unsigned offset = 0;
+ for (unsigned int i = 0; i < block->NumUniforms; i++) {
+ struct gl_uniform_buffer_variable *ubo_var = &block->Uniforms[i];
+ const struct glsl_type *type = ubo_var->Type;
+
+ unsigned alignment = type->std140_base_alignment(ubo_var->RowMajor);
+ unsigned size = type->std140_size(ubo_var->RowMajor);
+
+ offset = align(offset, alignment);
+ ubo_var->Offset = offset;
+ offset += size;
+ }
+ block->UniformBufferSize = offset;
+ }
+}
+
void
link_assign_uniform_locations(struct gl_shader_program *prog)
{
@@ -340,6 +507,14 @@ link_assign_uniform_locations(struct gl_shader_program *prog)
*/
memset(prog->SamplerUnits, 0, sizeof(prog->SamplerUnits));
+ for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) {
+ if (prog->_LinkedShaders[i] == NULL)
+ continue;
+
+ if (!link_update_uniform_buffer_variables(prog->_LinkedShaders[i]))
+ return;
+ }
+
/* First pass: Count the uniform resources used by the user-defined
* uniforms. While this happens, each active uniform will have an index
* assigned to it.
@@ -412,7 +587,7 @@ link_assign_uniform_locations(struct gl_shader_program *prog)
if (strncmp("gl_", var->name, 3) == 0)
continue;
- parcel.process(var);
+ parcel.set_and_process(prog, var);
}
prog->_LinkedShaders[i]->active_samplers = parcel.shader_samplers_used;
diff --git a/mesalib/src/glsl/linker.cpp b/mesalib/src/glsl/linker.cpp
index f06298cf6..bfdde4023 100644
--- a/mesalib/src/glsl/linker.cpp
+++ b/mesalib/src/glsl/linker.cpp
@@ -581,6 +581,48 @@ cross_validate_uniforms(struct gl_shader_program *prog)
MESA_SHADER_TYPES, true);
}
+/**
+ * Accumulates the array of prog->UniformBlocks and checks that all
+ * definitons of blocks agree on their contents.
+ */
+static bool
+interstage_cross_validate_uniform_blocks(struct gl_shader_program *prog)
+{
+ unsigned max_num_uniform_blocks = 0;
+ for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) {
+ if (prog->_LinkedShaders[i])
+ max_num_uniform_blocks += prog->_LinkedShaders[i]->NumUniformBlocks;
+ }
+
+ for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) {
+ struct gl_shader *sh = prog->_LinkedShaders[i];
+
+ prog->UniformBlockStageIndex[i] = ralloc_array(prog, int,
+ max_num_uniform_blocks);
+ for (unsigned int j = 0; j < max_num_uniform_blocks; j++)
+ prog->UniformBlockStageIndex[i][j] = -1;
+
+ if (sh == NULL)
+ continue;
+
+ for (unsigned int j = 0; j < sh->NumUniformBlocks; j++) {
+ int index = link_cross_validate_uniform_block(prog,
+ &prog->UniformBlocks,
+ &prog->NumUniformBlocks,
+ &sh->UniformBlocks[j]);
+
+ if (index == -1) {
+ linker_error(prog, "uniform block `%s' has mismatching definitions",
+ sh->UniformBlocks[j].Name);
+ return false;
+ }
+
+ prog->UniformBlockStageIndex[i][index] = j;
+ }
+ }
+
+ return true;
+}
/**
* Validate that outputs from one stage match inputs of another
@@ -910,7 +952,6 @@ public:
}
};
-
/**
* Combine a group of shaders for a single stage to generate a linked shader
*
@@ -925,11 +966,33 @@ link_intrastage_shaders(void *mem_ctx,
struct gl_shader **shader_list,
unsigned num_shaders)
{
+ struct gl_uniform_block *uniform_blocks = NULL;
+ unsigned num_uniform_blocks = 0;
+
/* Check that global variables defined in multiple shaders are consistent.
*/
if (!cross_validate_globals(prog, shader_list, num_shaders, false))
return NULL;
+ /* Check that uniform blocks between shaders for a stage agree. */
+ for (unsigned i = 0; i < num_shaders; i++) {
+ struct gl_shader *sh = shader_list[i];
+
+ for (unsigned j = 0; j < shader_list[i]->NumUniformBlocks; j++) {
+ link_assign_uniform_block_offsets(shader_list[i]);
+
+ int index = link_cross_validate_uniform_block(mem_ctx,
+ &uniform_blocks,
+ &num_uniform_blocks,
+ &sh->UniformBlocks[j]);
+ if (index == -1) {
+ linker_error(prog, "uniform block `%s' has mismatching definitions",
+ sh->UniformBlocks[j].Name);
+ return NULL;
+ }
+ }
+ }
+
/* Check that there is only a single definition of each function signature
* across all shaders.
*/
@@ -997,6 +1060,10 @@ link_intrastage_shaders(void *mem_ctx,
linked->ir = new(linked) exec_list;
clone_ir_list(mem_ctx, linked->ir, main->ir);
+ linked->UniformBlocks = uniform_blocks;
+ linked->NumUniformBlocks = num_uniform_blocks;
+ ralloc_steal(linked, linked->UniformBlocks);
+
populate_symbol_table(linked);
/* The a pointer to the main function in the final linked shader (i.e., the
@@ -1100,6 +1167,13 @@ update_array_sizes(struct gl_shader_program *prog)
!var->type->is_array())
continue;
+ /* GL_ARB_uniform_buffer_object says that std140 uniforms
+ * will not be eliminated. Since we always do std140, just
+ * don't resize arrays in UBOs.
+ */
+ if (var->uniform_block != -1)
+ continue;
+
unsigned int size = var->max_array_access;
for (unsigned j = 0; j < MESA_SHADER_TYPES; j++) {
if (prog->_LinkedShaders[j] == NULL)
@@ -2289,11 +2363,17 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
prog->Validated = false;
prog->_Used = false;
- if (prog->InfoLog != NULL)
- ralloc_free(prog->InfoLog);
-
+ ralloc_free(prog->InfoLog);
prog->InfoLog = ralloc_strdup(NULL, "");
+ ralloc_free(prog->UniformBlocks);
+ prog->UniformBlocks = NULL;
+ prog->NumUniformBlocks = 0;
+ for (int i = 0; i < MESA_SHADER_TYPES; i++) {
+ ralloc_free(prog->UniformBlockStageIndex[i]);
+ prog->UniformBlockStageIndex[i] = NULL;
+ }
+
/* Separate the shaders into groups based on their type.
*/
struct gl_shader **vert_shader_list;
@@ -2422,6 +2502,9 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
}
}
+ if (!interstage_cross_validate_uniform_blocks(prog))
+ goto done;
+
/* Do common optimization before assigning storage for attributes,
* uniforms, and varyings. Later optimization could possibly make
* some of that unused.
diff --git a/mesalib/src/glsl/linker.h b/mesalib/src/glsl/linker.h
index d0aaf3e1e..7d2e98a15 100644
--- a/mesalib/src/glsl/linker.h
+++ b/mesalib/src/glsl/linker.h
@@ -40,6 +40,15 @@ link_assign_uniform_locations(struct gl_shader_program *prog);
extern void
link_set_uniform_initializers(struct gl_shader_program *prog);
+extern int
+link_cross_validate_uniform_block(void *mem_ctx,
+ struct gl_uniform_block **linked_blocks,
+ unsigned int *num_linked_blocks,
+ struct gl_uniform_block *new_block);
+
+void
+link_assign_uniform_block_offsets(struct gl_shader *shader);
+
/**
* Class for processing all of the leaf fields of an uniform
*
diff --git a/mesalib/src/glsl/lower_vector.cpp b/mesalib/src/glsl/lower_vector.cpp
index 57963a121..0cd6909db 100644
--- a/mesalib/src/glsl/lower_vector.cpp
+++ b/mesalib/src/glsl/lower_vector.cpp
@@ -183,7 +183,7 @@ lower_vector_visitor::handle_rvalue(ir_rvalue **rvalue)
if (assigned > 0) {
ir_constant *const c =
new(mem_ctx) ir_constant(glsl_type::get_instance(expr->type->base_type,
- assigned, 0),
+ assigned, 1),
&d);
ir_dereference *const lhs = new(mem_ctx) ir_dereference_variable(temp);
ir_assignment *const assign =
diff --git a/mesalib/src/glsl/opt_dead_code.cpp b/mesalib/src/glsl/opt_dead_code.cpp
index 0578f1737..de8475f95 100644
--- a/mesalib/src/glsl/opt_dead_code.cpp
+++ b/mesalib/src/glsl/opt_dead_code.cpp
@@ -95,9 +95,15 @@ do_dead_code(exec_list *instructions, bool uniform_locations_assigned)
/* uniform initializers are precious, and could get used by another
* stage. Also, once uniform locations have been assigned, the
* declaration cannot be deleted.
+ *
+ * Also, GL_ARB_uniform_buffer_object says that std140
+ * uniforms will not be eliminated. Since we always do
+ * std140, just don't eliminate uniforms in UBOs.
*/
if (entry->var->mode == ir_var_uniform &&
- (uniform_locations_assigned || entry->var->constant_value))
+ (uniform_locations_assigned ||
+ entry->var->constant_value ||
+ entry->var->uniform_block != -1))
continue;
entry->var->remove();
diff --git a/mesalib/src/glsl/strtod.c b/mesalib/src/glsl/strtod.c
index a876e138b..47c1f0ed6 100644
--- a/mesalib/src/glsl/strtod.c
+++ b/mesalib/src/glsl/strtod.c
@@ -45,7 +45,7 @@ double
glsl_strtod(const char *s, char **end)
{
#if defined(_GNU_SOURCE) && !defined(__CYGWIN__) && !defined(__FreeBSD__) && \
- !defined(__HAIKU__)
+ !defined(__HAIKU__) && !defined(__UCLIBC__)
static locale_t loc = NULL;
if (!loc) {
loc = newlocale(LC_CTYPE_MASK, "C", NULL);