*/
#include <stdio.h>
-#include <stdlib.h>
-#include "main/core.h" /* for Elements */
-#include "glsl_symbol_table.h"
+#include "main/core.h" /* for Elements, MAX2 */
#include "glsl_parser_extras.h"
#include "glsl_types.h"
-extern "C" {
#include "program/hash_table.h"
-}
+
+mtx_t glsl_type::mutex = _MTX_INITIALIZER_NP;
hash_table *glsl_type::array_types = NULL;
hash_table *glsl_type::record_types = NULL;
hash_table *glsl_type::interface_types = NULL;
vector_elements(vector_elements), matrix_columns(matrix_columns),
length(0)
{
+ mtx_lock(&glsl_type::mutex);
+
init_ralloc_type_ctx();
assert(name != NULL);
this->name = ralloc_strdup(this->mem_ctx, name);
+
+ mtx_unlock(&glsl_type::mutex);
+
/* Neither dimension is zero or both dimensions are zero.
*/
assert((vector_elements == 0) == (matrix_columns == 0));
sampler_array(array), sampler_type(type), interface_packing(0),
length(0)
{
+ mtx_lock(&glsl_type::mutex);
+
init_ralloc_type_ctx();
assert(name != NULL);
this->name = ralloc_strdup(this->mem_ctx, name);
+
+ mtx_unlock(&glsl_type::mutex);
+
memset(& fields, 0, sizeof(fields));
if (base_type == GLSL_TYPE_SAMPLER) {
{
unsigned int i;
+ mtx_lock(&glsl_type::mutex);
+
init_ralloc_type_ctx();
assert(name != NULL);
this->name = ralloc_strdup(this->mem_ctx, name);
this->fields.structure = ralloc_array(this->mem_ctx,
glsl_struct_field, length);
+
for (i = 0; i < length; i++) {
this->fields.structure[i].type = fields[i].type;
this->fields.structure[i].name = ralloc_strdup(this->fields.structure,
this->fields.structure[i].interpolation = fields[i].interpolation;
this->fields.structure[i].centroid = fields[i].centroid;
this->fields.structure[i].sample = fields[i].sample;
- this->fields.structure[i].row_major = fields[i].row_major;
+ this->fields.structure[i].matrix_layout = fields[i].matrix_layout;
}
+
+ mtx_unlock(&glsl_type::mutex);
}
glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields,
{
unsigned int i;
+ mtx_lock(&glsl_type::mutex);
+
init_ralloc_type_ctx();
assert(name != NULL);
this->name = ralloc_strdup(this->mem_ctx, name);
this->fields.structure[i].interpolation = fields[i].interpolation;
this->fields.structure[i].centroid = fields[i].centroid;
this->fields.structure[i].sample = fields[i].sample;
- this->fields.structure[i].row_major = fields[i].row_major;
+ this->fields.structure[i].matrix_layout = fields[i].matrix_layout;
}
+
+ mtx_unlock(&glsl_type::mutex);
}
void
_mesa_glsl_release_types(void)
{
+ mtx_lock(&glsl_type::mutex);
+
if (glsl_type::array_types != NULL) {
hash_table_dtor(glsl_type::array_types);
glsl_type::array_types = NULL;
hash_table_dtor(glsl_type::record_types);
glsl_type::record_types = NULL;
}
+
+ mtx_unlock(&glsl_type::mutex);
}
sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
sampler_type(0), interface_packing(0),
vector_elements(0), matrix_columns(0),
- name(NULL), length(length)
+ length(length), name(NULL)
{
this->fields.array = array;
/* Inherit the gl type of the base. The GL type is used for
* NUL.
*/
const unsigned name_length = strlen(array->name) + 10 + 3;
+
+ mtx_lock(&glsl_type::mutex);
char *const n = (char *) ralloc_size(this->mem_ctx, name_length);
+ mtx_unlock(&glsl_type::mutex);
if (length == 0)
snprintf(n, name_length, "%s[]", array->name);
const glsl_type *
glsl_type::get_array_instance(const glsl_type *base, unsigned array_size)
{
-
- if (array_types == NULL) {
- array_types = hash_table_ctor(64, hash_table_string_hash,
- hash_table_string_compare);
- }
-
/* Generate a name using the base type pointer in the key. This is
* done because the name of the base type may not be unique across
* shaders. For example, two shaders may have different record types
char key[128];
snprintf(key, sizeof(key), "%p[%u]", (void *) base, array_size);
+ mtx_lock(&glsl_type::mutex);
+
+ if (array_types == NULL) {
+ array_types = hash_table_ctor(64, hash_table_string_hash,
+ hash_table_string_compare);
+ }
+
const glsl_type *t = (glsl_type *) hash_table_find(array_types, key);
+
if (t == NULL) {
+ mtx_unlock(&glsl_type::mutex);
t = new glsl_type(base, array_size);
+ mtx_lock(&glsl_type::mutex);
hash_table_insert(array_types, (void *) t, ralloc_strdup(mem_ctx, key));
}
assert(t->length == array_size);
assert(t->fields.array == base);
+ mtx_unlock(&glsl_type::mutex);
+
return t;
}
if (this->interface_packing != b->interface_packing)
return false;
+ /* From the GLSL 4.20 specification (Sec 4.2):
+ *
+ * "Structures must have the same name, sequence of type names, and
+ * type definitions, and field names to be considered the same type."
+ *
+ * GLSL ES behaves the same (Ver 1.00 Sec 4.2.4, Ver 3.00 Sec 4.2.5).
+ *
+ * Note that we cannot force type name check when comparing unnamed
+ * structure types, these have a unique name assigned during parsing.
+ */
+ if (!this->is_anonymous() && !b->is_anonymous())
+ if (strcmp(this->name, b->name) != 0)
+ return false;
+
for (unsigned i = 0; i < this->length; i++) {
if (this->fields.structure[i].type != b->fields.structure[i].type)
return false;
if (strcmp(this->fields.structure[i].name,
b->fields.structure[i].name) != 0)
return false;
- if (this->fields.structure[i].row_major
- != b->fields.structure[i].row_major)
+ if (this->fields.structure[i].matrix_layout
+ != b->fields.structure[i].matrix_layout)
return false;
if (this->fields.structure[i].location
!= b->fields.structure[i].location)
{
const glsl_type key(fields, num_fields, name);
+ mtx_lock(&glsl_type::mutex);
+
if (record_types == NULL) {
record_types = hash_table_ctor(64, record_key_hash, record_key_compare);
}
const glsl_type *t = (glsl_type *) hash_table_find(record_types, & key);
if (t == NULL) {
+ mtx_unlock(&glsl_type::mutex);
t = new glsl_type(fields, num_fields, name);
+ mtx_lock(&glsl_type::mutex);
hash_table_insert(record_types, (void *) t, t);
}
assert(t->length == num_fields);
assert(strcmp(t->name, name) == 0);
+ mtx_unlock(&glsl_type::mutex);
+
return t;
}
{
const glsl_type key(fields, num_fields, packing, block_name);
+ mtx_lock(&glsl_type::mutex);
+
if (interface_types == NULL) {
interface_types = hash_table_ctor(64, record_key_hash, record_key_compare);
}
const glsl_type *t = (glsl_type *) hash_table_find(interface_types, & key);
if (t == NULL) {
+ mtx_unlock(&glsl_type::mutex);
t = new glsl_type(fields, num_fields, packing, block_name);
+ mtx_lock(&glsl_type::mutex);
hash_table_insert(interface_types, (void *) t, t);
}
assert(t->length == num_fields);
assert(strcmp(t->name, block_name) == 0);
+ mtx_unlock(&glsl_type::mutex);
+
return t;
}
return 0;
}
+unsigned
+glsl_type::uniform_locations() const
+{
+ unsigned size = 0;
+
+ switch (this->base_type) {
+ case GLSL_TYPE_UINT:
+ case GLSL_TYPE_INT:
+ case GLSL_TYPE_FLOAT:
+ case GLSL_TYPE_BOOL:
+ case GLSL_TYPE_SAMPLER:
+ case GLSL_TYPE_IMAGE:
+ return 1;
+
+ case GLSL_TYPE_STRUCT:
+ case GLSL_TYPE_INTERFACE:
+ for (unsigned i = 0; i < this->length; i++)
+ size += this->fields.structure[i].type->uniform_locations();
+ return size;
+ case GLSL_TYPE_ARRAY:
+ return this->length * this->fields.array->uniform_locations();
+ default:
+ return 0;
+ }
+}
+
bool
-glsl_type::can_implicitly_convert_to(const glsl_type *desired) const
+glsl_type::can_implicitly_convert_to(const glsl_type *desired,
+ _mesa_glsl_parse_state *state) const
{
if (this == desired)
return true;
if (this->matrix_columns > 1 || desired->matrix_columns > 1)
return false;
+ /* Vector size must match. */
+ if (this->vector_elements != desired->vector_elements)
+ return false;
+
/* int and uint can be converted to float. */
- return desired->is_float()
- && this->is_integer()
- && this->vector_elements == desired->vector_elements;
+ if (desired->is_float() && this->is_integer())
+ return true;
+
+ /* With GLSL 4.0 / ARB_gpu_shader5, int can be converted to uint.
+ * Note that state may be NULL here, when resolving function calls in the
+ * linker. By this time, all the state-dependent checks have already
+ * happened though, so allow anything that's allowed in any shader version. */
+ if ((!state || state->is_version(400, 0) || state->ARB_gpu_shader5_enable) &&
+ desired->base_type == GLSL_TYPE_UINT && this->base_type == GLSL_TYPE_INT)
+ return true;
+
+ return false;
}
unsigned
if (this->is_record()) {
unsigned base_alignment = 16;
for (unsigned i = 0; i < this->length; i++) {
+ bool field_row_major = row_major;
+ const enum glsl_matrix_layout matrix_layout =
+ glsl_matrix_layout(this->fields.structure[i].matrix_layout);
+ if (matrix_layout == GLSL_MATRIX_LAYOUT_ROW_MAJOR) {
+ field_row_major = true;
+ } else if (matrix_layout == GLSL_MATRIX_LAYOUT_COLUMN_MAJOR) {
+ field_row_major = false;
+ }
+
const struct glsl_type *field_type = this->fields.structure[i].type;
base_alignment = MAX2(base_alignment,
- field_type->std140_base_alignment(row_major));
+ field_type->std140_base_alignment(field_row_major));
}
return base_alignment;
}
* 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())) {
+ if (this->without_array()->is_matrix()) {
const struct glsl_type *element_type;
const struct glsl_type *vec_type;
unsigned int array_len;
*/
if (this->is_record()) {
unsigned size = 0;
+ unsigned max_align = 0;
+
for (unsigned i = 0; i < this->length; i++) {
+ bool field_row_major = row_major;
+ const enum glsl_matrix_layout matrix_layout =
+ glsl_matrix_layout(this->fields.structure[i].matrix_layout);
+ if (matrix_layout == GLSL_MATRIX_LAYOUT_ROW_MAJOR) {
+ field_row_major = true;
+ } else if (matrix_layout == GLSL_MATRIX_LAYOUT_COLUMN_MAJOR) {
+ field_row_major = false;
+ }
+
const struct glsl_type *field_type = this->fields.structure[i].type;
- unsigned align = field_type->std140_base_alignment(row_major);
+ unsigned align = field_type->std140_base_alignment(field_row_major);
size = glsl_align(size, align);
- size += field_type->std140_size(row_major);
+ size += field_type->std140_size(field_row_major);
+
+ max_align = MAX2(align, max_align);
+
+ if (field_type->is_record() && (i + 1 < this->length))
+ size = glsl_align(size, 16);
}
- size = glsl_align(size,
- this->fields.structure[0].type->std140_base_alignment(row_major));
+ size = glsl_align(size, MAX2(max_align, 16));
return size;
}