2010-02-22 21:19:34 +00:00
|
|
|
/*
|
|
|
|
* Copyright © 2009 Intel Corporation
|
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
|
|
* to deal in the Software without restriction, including without limitation
|
|
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice (including the next
|
|
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
|
|
* Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
* DEALINGS IN THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
2011-02-10 18:26:42 +00:00
|
|
|
#include <stdio.h>
|
2014-06-09 23:57:36 +01:00
|
|
|
#include "main/core.h" /* for Elements, MAX2 */
|
2010-02-22 21:19:34 +00:00
|
|
|
#include "glsl_parser_extras.h"
|
|
|
|
#include "glsl_types.h"
|
2015-07-13 22:37:59 +01:00
|
|
|
#include "util/hash_table.h"
|
2014-12-15 23:41:58 +00:00
|
|
|
|
2010-02-22 21:19:34 +00:00
|
|
|
|
2014-08-20 07:40:29 +01:00
|
|
|
mtx_t glsl_type::mutex = _MTX_INITIALIZER_NP;
|
2010-03-31 00:58:19 +01:00
|
|
|
hash_table *glsl_type::array_types = NULL;
|
2010-06-28 19:54:57 +01:00
|
|
|
hash_table *glsl_type::record_types = NULL;
|
2012-12-11 20:11:16 +00:00
|
|
|
hash_table *glsl_type::interface_types = NULL;
|
2015-04-20 01:16:55 +01:00
|
|
|
hash_table *glsl_type::subroutine_types = NULL;
|
2010-08-04 04:05:53 +01:00
|
|
|
void *glsl_type::mem_ctx = NULL;
|
2010-03-31 00:58:19 +01:00
|
|
|
|
2010-08-02 19:35:14 +01:00
|
|
|
void
|
2011-01-21 22:32:31 +00:00
|
|
|
glsl_type::init_ralloc_type_ctx(void)
|
2010-07-27 19:14:59 +01:00
|
|
|
{
|
2010-08-04 04:05:53 +01:00
|
|
|
if (glsl_type::mem_ctx == NULL) {
|
2011-01-21 22:32:31 +00:00
|
|
|
glsl_type::mem_ctx = ralloc_autofree_context();
|
2010-08-04 04:05:53 +01:00
|
|
|
assert(glsl_type::mem_ctx != NULL);
|
2010-07-27 19:14:59 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-06-28 19:09:40 +01:00
|
|
|
glsl_type::glsl_type(GLenum gl_type,
|
2010-11-11 07:20:47 +00:00
|
|
|
glsl_base_type base_type, unsigned vector_elements,
|
2010-06-28 19:09:40 +01:00
|
|
|
unsigned matrix_columns, const char *name) :
|
|
|
|
gl_type(gl_type),
|
|
|
|
base_type(base_type),
|
|
|
|
sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
|
2012-12-11 20:11:16 +00:00
|
|
|
sampler_type(0), interface_packing(0),
|
2010-06-28 19:09:40 +01:00
|
|
|
vector_elements(vector_elements), matrix_columns(matrix_columns),
|
|
|
|
length(0)
|
|
|
|
{
|
2014-08-20 07:40:29 +01:00
|
|
|
mtx_lock(&glsl_type::mutex);
|
|
|
|
|
2011-01-21 22:32:31 +00:00
|
|
|
init_ralloc_type_ctx();
|
2013-04-10 04:36:30 +01:00
|
|
|
assert(name != NULL);
|
2011-01-21 22:32:31 +00:00
|
|
|
this->name = ralloc_strdup(this->mem_ctx, name);
|
2014-08-20 07:40:29 +01:00
|
|
|
|
|
|
|
mtx_unlock(&glsl_type::mutex);
|
|
|
|
|
2010-06-28 19:09:40 +01:00
|
|
|
/* Neither dimension is zero or both dimensions are zero.
|
|
|
|
*/
|
|
|
|
assert((vector_elements == 0) == (matrix_columns == 0));
|
|
|
|
memset(& fields, 0, sizeof(fields));
|
|
|
|
}
|
|
|
|
|
2013-11-25 21:50:47 +00:00
|
|
|
glsl_type::glsl_type(GLenum gl_type, glsl_base_type base_type,
|
2010-06-28 19:09:40 +01:00
|
|
|
enum glsl_sampler_dim dim, bool shadow, bool array,
|
|
|
|
unsigned type, const char *name) :
|
|
|
|
gl_type(gl_type),
|
2013-11-25 21:50:47 +00:00
|
|
|
base_type(base_type),
|
2010-06-28 19:09:40 +01:00
|
|
|
sampler_dimensionality(dim), sampler_shadow(shadow),
|
2012-12-11 20:11:16 +00:00
|
|
|
sampler_array(array), sampler_type(type), interface_packing(0),
|
2010-06-28 19:09:40 +01:00
|
|
|
length(0)
|
|
|
|
{
|
2014-08-20 07:40:29 +01:00
|
|
|
mtx_lock(&glsl_type::mutex);
|
|
|
|
|
2011-01-21 22:32:31 +00:00
|
|
|
init_ralloc_type_ctx();
|
2013-04-10 04:36:30 +01:00
|
|
|
assert(name != NULL);
|
2011-01-21 22:32:31 +00:00
|
|
|
this->name = ralloc_strdup(this->mem_ctx, name);
|
2014-08-20 07:40:29 +01:00
|
|
|
|
|
|
|
mtx_unlock(&glsl_type::mutex);
|
|
|
|
|
2010-06-28 19:09:40 +01:00
|
|
|
memset(& fields, 0, sizeof(fields));
|
2013-11-25 21:50:47 +00:00
|
|
|
|
|
|
|
if (base_type == GLSL_TYPE_SAMPLER) {
|
|
|
|
/* Samplers take no storage whatsoever. */
|
|
|
|
matrix_columns = vector_elements = 0;
|
|
|
|
} else {
|
|
|
|
matrix_columns = vector_elements = 1;
|
|
|
|
}
|
2010-06-28 19:09:40 +01:00
|
|
|
}
|
|
|
|
|
2010-06-28 19:57:38 +01:00
|
|
|
glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields,
|
|
|
|
const char *name) :
|
2013-02-08 06:46:43 +00:00
|
|
|
gl_type(0),
|
2010-06-28 19:57:38 +01:00
|
|
|
base_type(GLSL_TYPE_STRUCT),
|
|
|
|
sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
|
2012-12-11 20:11:16 +00:00
|
|
|
sampler_type(0), interface_packing(0),
|
|
|
|
vector_elements(0), matrix_columns(0),
|
|
|
|
length(num_fields)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
2014-08-20 07:40:29 +01:00
|
|
|
mtx_lock(&glsl_type::mutex);
|
|
|
|
|
2012-12-11 20:11:16 +00:00
|
|
|
init_ralloc_type_ctx();
|
2013-04-10 04:36:30 +01:00
|
|
|
assert(name != NULL);
|
2012-12-11 20:11:16 +00:00
|
|
|
this->name = ralloc_strdup(this->mem_ctx, name);
|
|
|
|
this->fields.structure = ralloc_array(this->mem_ctx,
|
|
|
|
glsl_struct_field, length);
|
2014-08-20 07:40:29 +01:00
|
|
|
|
2012-12-11 20:11:16 +00:00
|
|
|
for (i = 0; i < length; i++) {
|
|
|
|
this->fields.structure[i].type = fields[i].type;
|
|
|
|
this->fields.structure[i].name = ralloc_strdup(this->fields.structure,
|
|
|
|
fields[i].name);
|
2013-09-10 00:39:47 +01:00
|
|
|
this->fields.structure[i].location = fields[i].location;
|
2013-10-22 23:11:51 +01:00
|
|
|
this->fields.structure[i].interpolation = fields[i].interpolation;
|
|
|
|
this->fields.structure[i].centroid = fields[i].centroid;
|
2013-11-29 08:26:10 +00:00
|
|
|
this->fields.structure[i].sample = fields[i].sample;
|
2014-07-17 00:51:14 +01:00
|
|
|
this->fields.structure[i].matrix_layout = fields[i].matrix_layout;
|
2014-03-05 12:43:17 +00:00
|
|
|
this->fields.structure[i].patch = fields[i].patch;
|
2012-12-11 20:11:16 +00:00
|
|
|
}
|
2014-08-20 07:40:29 +01:00
|
|
|
|
|
|
|
mtx_unlock(&glsl_type::mutex);
|
2012-12-11 20:11:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields,
|
|
|
|
enum glsl_interface_packing packing, const char *name) :
|
2013-02-08 06:46:43 +00:00
|
|
|
gl_type(0),
|
2012-12-11 20:11:16 +00:00
|
|
|
base_type(GLSL_TYPE_INTERFACE),
|
|
|
|
sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
|
|
|
|
sampler_type(0), interface_packing((unsigned) packing),
|
2010-06-28 19:57:38 +01:00
|
|
|
vector_elements(0), matrix_columns(0),
|
|
|
|
length(num_fields)
|
|
|
|
{
|
2010-07-21 00:47:25 +01:00
|
|
|
unsigned int i;
|
|
|
|
|
2014-08-20 07:40:29 +01:00
|
|
|
mtx_lock(&glsl_type::mutex);
|
|
|
|
|
2011-01-21 22:32:31 +00:00
|
|
|
init_ralloc_type_ctx();
|
2013-04-10 04:36:30 +01:00
|
|
|
assert(name != NULL);
|
2011-01-21 22:32:31 +00:00
|
|
|
this->name = ralloc_strdup(this->mem_ctx, name);
|
|
|
|
this->fields.structure = ralloc_array(this->mem_ctx,
|
2010-07-21 00:47:25 +01:00
|
|
|
glsl_struct_field, length);
|
|
|
|
for (i = 0; i < length; i++) {
|
|
|
|
this->fields.structure[i].type = fields[i].type;
|
2011-01-21 22:32:31 +00:00
|
|
|
this->fields.structure[i].name = ralloc_strdup(this->fields.structure,
|
2010-07-21 00:47:25 +01:00
|
|
|
fields[i].name);
|
2013-09-10 00:39:47 +01:00
|
|
|
this->fields.structure[i].location = fields[i].location;
|
2013-10-22 23:11:51 +01:00
|
|
|
this->fields.structure[i].interpolation = fields[i].interpolation;
|
|
|
|
this->fields.structure[i].centroid = fields[i].centroid;
|
2013-11-29 08:26:10 +00:00
|
|
|
this->fields.structure[i].sample = fields[i].sample;
|
2014-07-17 00:51:14 +01:00
|
|
|
this->fields.structure[i].matrix_layout = fields[i].matrix_layout;
|
2014-03-05 12:43:17 +00:00
|
|
|
this->fields.structure[i].patch = fields[i].patch;
|
2010-07-21 00:47:25 +01:00
|
|
|
}
|
2014-08-20 07:40:29 +01:00
|
|
|
|
|
|
|
mtx_unlock(&glsl_type::mutex);
|
2010-06-28 19:57:38 +01:00
|
|
|
}
|
|
|
|
|
2015-04-20 01:16:55 +01:00
|
|
|
glsl_type::glsl_type(const char *subroutine_name) :
|
|
|
|
gl_type(0),
|
|
|
|
base_type(GLSL_TYPE_SUBROUTINE),
|
|
|
|
sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
|
|
|
|
sampler_type(0), interface_packing(0),
|
|
|
|
vector_elements(0), matrix_columns(0),
|
|
|
|
length(0)
|
|
|
|
{
|
|
|
|
mtx_lock(&glsl_type::mutex);
|
|
|
|
|
|
|
|
init_ralloc_type_ctx();
|
|
|
|
assert(subroutine_name != NULL);
|
|
|
|
this->name = ralloc_strdup(this->mem_ctx, subroutine_name);
|
|
|
|
this->vector_elements = 1;
|
|
|
|
mtx_unlock(&glsl_type::mutex);
|
|
|
|
}
|
2010-02-22 21:19:34 +00:00
|
|
|
|
2011-07-12 00:44:13 +01:00
|
|
|
bool
|
|
|
|
glsl_type::contains_sampler() const
|
|
|
|
{
|
|
|
|
if (this->is_array()) {
|
|
|
|
return this->fields.array->contains_sampler();
|
|
|
|
} else if (this->is_record()) {
|
|
|
|
for (unsigned int i = 0; i < this->length; i++) {
|
|
|
|
if (this->fields.structure[i].type->contains_sampler())
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
return this->is_sampler();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-07 00:09:39 +00:00
|
|
|
|
|
|
|
bool
|
|
|
|
glsl_type::contains_integer() const
|
|
|
|
{
|
|
|
|
if (this->is_array()) {
|
|
|
|
return this->fields.array->contains_integer();
|
|
|
|
} else if (this->is_record()) {
|
|
|
|
for (unsigned int i = 0; i < this->length; i++) {
|
|
|
|
if (this->fields.structure[i].type->contains_integer())
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
return this->is_integer();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-05 09:38:44 +00:00
|
|
|
bool
|
|
|
|
glsl_type::contains_double() const
|
|
|
|
{
|
|
|
|
if (this->is_array()) {
|
|
|
|
return this->fields.array->contains_double();
|
|
|
|
} else if (this->is_record()) {
|
|
|
|
for (unsigned int i = 0; i < this->length; i++) {
|
|
|
|
if (this->fields.structure[i].type->contains_double())
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
return this->is_double();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-20 22:58:03 +01:00
|
|
|
bool
|
|
|
|
glsl_type::contains_opaque() const {
|
|
|
|
switch (base_type) {
|
|
|
|
case GLSL_TYPE_SAMPLER:
|
2013-11-25 21:50:47 +00:00
|
|
|
case GLSL_TYPE_IMAGE:
|
2013-09-20 22:58:03 +01:00
|
|
|
case GLSL_TYPE_ATOMIC_UINT:
|
|
|
|
return true;
|
|
|
|
case GLSL_TYPE_ARRAY:
|
2015-04-30 11:45:54 +01:00
|
|
|
return fields.array->contains_opaque();
|
2013-09-20 22:58:03 +01:00
|
|
|
case GLSL_TYPE_STRUCT:
|
|
|
|
for (unsigned int i = 0; i < length; i++) {
|
|
|
|
if (fields.structure[i].type->contains_opaque())
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2013-02-07 00:09:39 +00:00
|
|
|
|
2015-04-20 01:16:55 +01:00
|
|
|
bool
|
|
|
|
glsl_type::contains_subroutine() const
|
|
|
|
{
|
|
|
|
if (this->is_array()) {
|
|
|
|
return this->fields.array->contains_subroutine();
|
|
|
|
} else if (this->is_record()) {
|
|
|
|
for (unsigned int i = 0; i < this->length; i++) {
|
|
|
|
if (this->fields.structure[i].type->contains_subroutine())
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
return this->is_subroutine();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-14 22:02:09 +00:00
|
|
|
gl_texture_index
|
|
|
|
glsl_type::sampler_index() const
|
|
|
|
{
|
|
|
|
const glsl_type *const t = (this->is_array()) ? this->fields.array : this;
|
|
|
|
|
|
|
|
assert(t->is_sampler());
|
|
|
|
|
|
|
|
switch (t->sampler_dimensionality) {
|
|
|
|
case GLSL_SAMPLER_DIM_1D:
|
|
|
|
return (t->sampler_array) ? TEXTURE_1D_ARRAY_INDEX : TEXTURE_1D_INDEX;
|
|
|
|
case GLSL_SAMPLER_DIM_2D:
|
|
|
|
return (t->sampler_array) ? TEXTURE_2D_ARRAY_INDEX : TEXTURE_2D_INDEX;
|
|
|
|
case GLSL_SAMPLER_DIM_3D:
|
|
|
|
return TEXTURE_3D_INDEX;
|
|
|
|
case GLSL_SAMPLER_DIM_CUBE:
|
2012-11-03 10:43:17 +00:00
|
|
|
return (t->sampler_array) ? TEXTURE_CUBE_ARRAY_INDEX : TEXTURE_CUBE_INDEX;
|
2011-11-14 22:02:09 +00:00
|
|
|
case GLSL_SAMPLER_DIM_RECT:
|
|
|
|
return TEXTURE_RECT_INDEX;
|
|
|
|
case GLSL_SAMPLER_DIM_BUF:
|
2012-01-17 02:01:22 +00:00
|
|
|
return TEXTURE_BUFFER_INDEX;
|
2011-11-14 22:02:09 +00:00
|
|
|
case GLSL_SAMPLER_DIM_EXTERNAL:
|
|
|
|
return TEXTURE_EXTERNAL_INDEX;
|
2012-12-21 08:33:37 +00:00
|
|
|
case GLSL_SAMPLER_DIM_MS:
|
|
|
|
return (t->sampler_array) ? TEXTURE_2D_MULTISAMPLE_ARRAY_INDEX : TEXTURE_2D_MULTISAMPLE_INDEX;
|
2011-11-14 22:02:09 +00:00
|
|
|
default:
|
|
|
|
assert(!"Should not get here.");
|
2012-01-17 02:01:22 +00:00
|
|
|
return TEXTURE_BUFFER_INDEX;
|
2011-11-14 22:02:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-25 22:03:06 +00:00
|
|
|
bool
|
|
|
|
glsl_type::contains_image() const
|
|
|
|
{
|
|
|
|
if (this->is_array()) {
|
|
|
|
return this->fields.array->contains_image();
|
|
|
|
} else if (this->is_record()) {
|
|
|
|
for (unsigned int i = 0; i < this->length; i++) {
|
|
|
|
if (this->fields.structure[i].type->contains_image())
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
return this->is_image();
|
|
|
|
}
|
|
|
|
}
|
2010-02-22 21:19:34 +00:00
|
|
|
|
2010-03-24 00:31:39 +00:00
|
|
|
const glsl_type *glsl_type::get_base_type() const
|
|
|
|
{
|
|
|
|
switch (base_type) {
|
|
|
|
case GLSL_TYPE_UINT:
|
2010-03-26 21:33:41 +00:00
|
|
|
return uint_type;
|
2010-03-24 00:31:39 +00:00
|
|
|
case GLSL_TYPE_INT:
|
2010-03-26 21:33:41 +00:00
|
|
|
return int_type;
|
2010-03-24 00:31:39 +00:00
|
|
|
case GLSL_TYPE_FLOAT:
|
2010-03-26 21:33:41 +00:00
|
|
|
return float_type;
|
2015-02-05 09:38:44 +00:00
|
|
|
case GLSL_TYPE_DOUBLE:
|
|
|
|
return double_type;
|
2010-03-24 00:31:39 +00:00
|
|
|
case GLSL_TYPE_BOOL:
|
2010-03-26 21:33:41 +00:00
|
|
|
return bool_type;
|
2010-03-24 00:31:39 +00:00
|
|
|
default:
|
2010-03-26 21:33:41 +00:00
|
|
|
return error_type;
|
2010-03-24 00:31:39 +00:00
|
|
|
}
|
|
|
|
}
|
2010-03-25 00:11:30 +00:00
|
|
|
|
|
|
|
|
2011-10-26 00:24:03 +01:00
|
|
|
const glsl_type *glsl_type::get_scalar_type() const
|
|
|
|
{
|
|
|
|
const glsl_type *type = this;
|
|
|
|
|
|
|
|
/* Handle arrays */
|
|
|
|
while (type->base_type == GLSL_TYPE_ARRAY)
|
|
|
|
type = type->fields.array;
|
|
|
|
|
|
|
|
/* Handle vectors and matrices */
|
|
|
|
switch (type->base_type) {
|
|
|
|
case GLSL_TYPE_UINT:
|
|
|
|
return uint_type;
|
|
|
|
case GLSL_TYPE_INT:
|
|
|
|
return int_type;
|
|
|
|
case GLSL_TYPE_FLOAT:
|
|
|
|
return float_type;
|
2015-02-05 09:38:44 +00:00
|
|
|
case GLSL_TYPE_DOUBLE:
|
|
|
|
return double_type;
|
2013-03-15 23:47:46 +00:00
|
|
|
case GLSL_TYPE_BOOL:
|
|
|
|
return bool_type;
|
2011-10-26 00:24:03 +01:00
|
|
|
default:
|
|
|
|
/* Handle everything else */
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-06-28 21:17:18 +01:00
|
|
|
void
|
|
|
|
_mesa_glsl_release_types(void)
|
|
|
|
{
|
2015-06-28 13:51:07 +01:00
|
|
|
/* Should only be called during atexit (either when unloading shared
|
|
|
|
* object, or if process terminates), so no mutex-locking should be
|
|
|
|
* necessary.
|
|
|
|
*/
|
2010-06-28 21:17:18 +01:00
|
|
|
if (glsl_type::array_types != NULL) {
|
2015-07-13 22:37:59 +01:00
|
|
|
_mesa_hash_table_destroy(glsl_type::array_types, NULL);
|
2010-06-28 21:17:18 +01:00
|
|
|
glsl_type::array_types = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (glsl_type::record_types != NULL) {
|
2015-07-13 22:37:59 +01:00
|
|
|
_mesa_hash_table_destroy(glsl_type::record_types, NULL);
|
2010-06-28 21:17:18 +01:00
|
|
|
glsl_type::record_types = NULL;
|
|
|
|
}
|
2015-07-13 22:41:26 +01:00
|
|
|
|
|
|
|
if (glsl_type::interface_types != NULL) {
|
|
|
|
_mesa_hash_table_destroy(glsl_type::interface_types, NULL);
|
|
|
|
glsl_type::interface_types = NULL;
|
|
|
|
}
|
2010-06-28 21:17:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-07-20 23:33:40 +01:00
|
|
|
glsl_type::glsl_type(const glsl_type *array, unsigned length) :
|
2010-03-31 22:37:42 +01:00
|
|
|
base_type(GLSL_TYPE_ARRAY),
|
|
|
|
sampler_dimensionality(0), sampler_shadow(0), sampler_array(0),
|
2012-12-11 20:11:16 +00:00
|
|
|
sampler_type(0), interface_packing(0),
|
2010-03-31 22:37:42 +01:00
|
|
|
vector_elements(0), matrix_columns(0),
|
2014-10-24 21:08:06 +01:00
|
|
|
length(length), name(NULL)
|
2010-03-31 22:37:42 +01:00
|
|
|
{
|
|
|
|
this->fields.array = array;
|
2010-07-12 22:02:59 +01:00
|
|
|
/* Inherit the gl type of the base. The GL type is used for
|
|
|
|
* uniform/statevar handling in Mesa and the arrayness of the type
|
|
|
|
* is represented by the size rather than the type.
|
|
|
|
*/
|
|
|
|
this->gl_type = array->gl_type;
|
2010-03-31 22:37:42 +01:00
|
|
|
|
|
|
|
/* Allow a maximum of 10 characters for the array size. This is enough
|
|
|
|
* for 32-bits of ~0. The extra 3 are for the '[', ']', and terminating
|
|
|
|
* NUL.
|
|
|
|
*/
|
|
|
|
const unsigned name_length = strlen(array->name) + 10 + 3;
|
2014-08-20 07:40:29 +01:00
|
|
|
|
|
|
|
mtx_lock(&glsl_type::mutex);
|
2011-01-21 22:32:31 +00:00
|
|
|
char *const n = (char *) ralloc_size(this->mem_ctx, name_length);
|
2014-08-20 07:40:29 +01:00
|
|
|
mtx_unlock(&glsl_type::mutex);
|
2010-03-31 22:37:42 +01:00
|
|
|
|
|
|
|
if (length == 0)
|
|
|
|
snprintf(n, name_length, "%s[]", array->name);
|
2014-01-23 12:21:02 +00:00
|
|
|
else {
|
|
|
|
/* insert outermost dimensions in the correct spot
|
|
|
|
* otherwise the dimension order will be backwards
|
|
|
|
*/
|
|
|
|
const char *pos = strchr(array->name, '[');
|
|
|
|
if (pos) {
|
|
|
|
int idx = pos - array->name;
|
|
|
|
snprintf(n, idx+1, "%s", array->name);
|
|
|
|
snprintf(n + idx, name_length - idx, "[%u]%s",
|
|
|
|
length, array->name + idx);
|
|
|
|
} else {
|
|
|
|
snprintf(n, name_length, "%s[%u]", array->name, length);
|
|
|
|
}
|
|
|
|
}
|
2010-03-31 22:37:42 +01:00
|
|
|
|
|
|
|
this->name = n;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-07-26 21:37:29 +01:00
|
|
|
const glsl_type *
|
2013-06-18 12:22:30 +01:00
|
|
|
glsl_type::vec(unsigned components)
|
|
|
|
{
|
|
|
|
if (components == 0 || components > 4)
|
|
|
|
return error_type;
|
|
|
|
|
|
|
|
static const glsl_type *const ts[] = {
|
|
|
|
float_type, vec2_type, vec3_type, vec4_type
|
|
|
|
};
|
|
|
|
return ts[components - 1];
|
|
|
|
}
|
|
|
|
|
2015-02-05 09:38:44 +00:00
|
|
|
const glsl_type *
|
|
|
|
glsl_type::dvec(unsigned components)
|
|
|
|
{
|
|
|
|
if (components == 0 || components > 4)
|
|
|
|
return error_type;
|
|
|
|
|
|
|
|
static const glsl_type *const ts[] = {
|
|
|
|
double_type, dvec2_type, dvec3_type, dvec4_type
|
|
|
|
};
|
|
|
|
return ts[components - 1];
|
|
|
|
}
|
2013-06-18 12:22:30 +01:00
|
|
|
|
2013-07-26 21:37:29 +01:00
|
|
|
const glsl_type *
|
2013-06-18 12:22:30 +01:00
|
|
|
glsl_type::ivec(unsigned components)
|
|
|
|
{
|
|
|
|
if (components == 0 || components > 4)
|
|
|
|
return error_type;
|
|
|
|
|
|
|
|
static const glsl_type *const ts[] = {
|
|
|
|
int_type, ivec2_type, ivec3_type, ivec4_type
|
|
|
|
};
|
|
|
|
return ts[components - 1];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-07-26 21:37:29 +01:00
|
|
|
const glsl_type *
|
2013-06-18 12:22:30 +01:00
|
|
|
glsl_type::uvec(unsigned components)
|
|
|
|
{
|
|
|
|
if (components == 0 || components > 4)
|
|
|
|
return error_type;
|
|
|
|
|
|
|
|
static const glsl_type *const ts[] = {
|
|
|
|
uint_type, uvec2_type, uvec3_type, uvec4_type
|
|
|
|
};
|
|
|
|
return ts[components - 1];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-07-26 21:37:29 +01:00
|
|
|
const glsl_type *
|
2013-06-18 12:22:30 +01:00
|
|
|
glsl_type::bvec(unsigned components)
|
|
|
|
{
|
|
|
|
if (components == 0 || components > 4)
|
|
|
|
return error_type;
|
|
|
|
|
|
|
|
static const glsl_type *const ts[] = {
|
|
|
|
bool_type, bvec2_type, bvec3_type, bvec4_type
|
|
|
|
};
|
|
|
|
return ts[components - 1];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-03-25 00:11:30 +00:00
|
|
|
const glsl_type *
|
|
|
|
glsl_type::get_instance(unsigned base_type, unsigned rows, unsigned columns)
|
|
|
|
{
|
2010-03-28 09:24:55 +01:00
|
|
|
if (base_type == GLSL_TYPE_VOID)
|
2010-12-13 19:19:38 +00:00
|
|
|
return void_type;
|
2010-03-28 09:24:55 +01:00
|
|
|
|
2010-03-25 00:11:30 +00:00
|
|
|
if ((rows < 1) || (rows > 4) || (columns < 1) || (columns > 4))
|
2010-03-26 21:33:41 +00:00
|
|
|
return error_type;
|
2010-03-25 00:11:30 +00:00
|
|
|
|
|
|
|
/* Treat GLSL vectors as Nx1 matrices.
|
|
|
|
*/
|
|
|
|
if (columns == 1) {
|
|
|
|
switch (base_type) {
|
|
|
|
case GLSL_TYPE_UINT:
|
glsl: Stop being clever with pointer arithmetic when fetching types.
Currently, vector types are linked together closely: the glsl_type
objects for float, vec2, vec3, and vec4 are all elements of the same
array, in that exact order. This makes it possible to obtain vector
types via pointer arithmetic on the scalar type's convenience pointer.
For example, float_type + (3 - 1) = vec3.
However, relying on this is extremely fragile. There's no particular
reason the underlying type objects need to be stored in an array. They
could be individual class members, possibly with padding between them.
Then the pointer arithmetic would break, and we'd get bad pointers to
non-heap allocated data, causing subtle breakage that can't be detected
by valgrind. Cue insanity.
Or someone could simply reorder the type variables, causing us to get
the wrong type entirely. Also cue insanity.
Writing this explicitly is much safer. With the new helper functions,
it's a bit less code even.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2013-06-18 12:22:31 +01:00
|
|
|
return uvec(rows);
|
2010-03-25 00:11:30 +00:00
|
|
|
case GLSL_TYPE_INT:
|
glsl: Stop being clever with pointer arithmetic when fetching types.
Currently, vector types are linked together closely: the glsl_type
objects for float, vec2, vec3, and vec4 are all elements of the same
array, in that exact order. This makes it possible to obtain vector
types via pointer arithmetic on the scalar type's convenience pointer.
For example, float_type + (3 - 1) = vec3.
However, relying on this is extremely fragile. There's no particular
reason the underlying type objects need to be stored in an array. They
could be individual class members, possibly with padding between them.
Then the pointer arithmetic would break, and we'd get bad pointers to
non-heap allocated data, causing subtle breakage that can't be detected
by valgrind. Cue insanity.
Or someone could simply reorder the type variables, causing us to get
the wrong type entirely. Also cue insanity.
Writing this explicitly is much safer. With the new helper functions,
it's a bit less code even.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2013-06-18 12:22:31 +01:00
|
|
|
return ivec(rows);
|
2010-03-25 00:11:30 +00:00
|
|
|
case GLSL_TYPE_FLOAT:
|
glsl: Stop being clever with pointer arithmetic when fetching types.
Currently, vector types are linked together closely: the glsl_type
objects for float, vec2, vec3, and vec4 are all elements of the same
array, in that exact order. This makes it possible to obtain vector
types via pointer arithmetic on the scalar type's convenience pointer.
For example, float_type + (3 - 1) = vec3.
However, relying on this is extremely fragile. There's no particular
reason the underlying type objects need to be stored in an array. They
could be individual class members, possibly with padding between them.
Then the pointer arithmetic would break, and we'd get bad pointers to
non-heap allocated data, causing subtle breakage that can't be detected
by valgrind. Cue insanity.
Or someone could simply reorder the type variables, causing us to get
the wrong type entirely. Also cue insanity.
Writing this explicitly is much safer. With the new helper functions,
it's a bit less code even.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2013-06-18 12:22:31 +01:00
|
|
|
return vec(rows);
|
2015-02-05 09:38:44 +00:00
|
|
|
case GLSL_TYPE_DOUBLE:
|
|
|
|
return dvec(rows);
|
2010-03-25 00:11:30 +00:00
|
|
|
case GLSL_TYPE_BOOL:
|
glsl: Stop being clever with pointer arithmetic when fetching types.
Currently, vector types are linked together closely: the glsl_type
objects for float, vec2, vec3, and vec4 are all elements of the same
array, in that exact order. This makes it possible to obtain vector
types via pointer arithmetic on the scalar type's convenience pointer.
For example, float_type + (3 - 1) = vec3.
However, relying on this is extremely fragile. There's no particular
reason the underlying type objects need to be stored in an array. They
could be individual class members, possibly with padding between them.
Then the pointer arithmetic would break, and we'd get bad pointers to
non-heap allocated data, causing subtle breakage that can't be detected
by valgrind. Cue insanity.
Or someone could simply reorder the type variables, causing us to get
the wrong type entirely. Also cue insanity.
Writing this explicitly is much safer. With the new helper functions,
it's a bit less code even.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2013-06-18 12:22:31 +01:00
|
|
|
return bvec(rows);
|
2010-03-25 00:11:30 +00:00
|
|
|
default:
|
2010-03-26 21:33:41 +00:00
|
|
|
return error_type;
|
2010-03-25 00:11:30 +00:00
|
|
|
}
|
|
|
|
} else {
|
2015-02-05 09:38:44 +00:00
|
|
|
if ((base_type != GLSL_TYPE_FLOAT && base_type != GLSL_TYPE_DOUBLE) || (rows == 1))
|
2010-03-26 21:33:41 +00:00
|
|
|
return error_type;
|
2010-03-25 00:11:30 +00:00
|
|
|
|
|
|
|
/* GLSL matrix types are named mat{COLUMNS}x{ROWS}. Only the following
|
|
|
|
* combinations are valid:
|
|
|
|
*
|
|
|
|
* 1 2 3 4
|
|
|
|
* 1
|
|
|
|
* 2 x x x
|
|
|
|
* 3 x x x
|
|
|
|
* 4 x x x
|
|
|
|
*/
|
|
|
|
#define IDX(c,r) (((c-1)*3) + (r-1))
|
|
|
|
|
2015-02-05 09:38:44 +00:00
|
|
|
if (base_type == GLSL_TYPE_DOUBLE) {
|
|
|
|
switch (IDX(columns, rows)) {
|
|
|
|
case IDX(2,2): return dmat2_type;
|
|
|
|
case IDX(2,3): return dmat2x3_type;
|
|
|
|
case IDX(2,4): return dmat2x4_type;
|
|
|
|
case IDX(3,2): return dmat3x2_type;
|
|
|
|
case IDX(3,3): return dmat3_type;
|
|
|
|
case IDX(3,4): return dmat3x4_type;
|
|
|
|
case IDX(4,2): return dmat4x2_type;
|
|
|
|
case IDX(4,3): return dmat4x3_type;
|
|
|
|
case IDX(4,4): return dmat4_type;
|
|
|
|
default: return error_type;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
switch (IDX(columns, rows)) {
|
|
|
|
case IDX(2,2): return mat2_type;
|
|
|
|
case IDX(2,3): return mat2x3_type;
|
|
|
|
case IDX(2,4): return mat2x4_type;
|
|
|
|
case IDX(3,2): return mat3x2_type;
|
|
|
|
case IDX(3,3): return mat3_type;
|
|
|
|
case IDX(3,4): return mat3x4_type;
|
|
|
|
case IDX(4,2): return mat4x2_type;
|
|
|
|
case IDX(4,3): return mat4x3_type;
|
|
|
|
case IDX(4,4): return mat4_type;
|
|
|
|
default: return error_type;
|
|
|
|
}
|
2010-03-25 00:11:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(!"Should not get here.");
|
2010-03-26 21:33:41 +00:00
|
|
|
return error_type;
|
2010-03-25 00:11:30 +00:00
|
|
|
}
|
2010-03-31 00:58:19 +01:00
|
|
|
|
2014-10-23 00:58:26 +01:00
|
|
|
const glsl_type *
|
|
|
|
glsl_type::get_sampler_instance(enum glsl_sampler_dim dim,
|
|
|
|
bool shadow,
|
|
|
|
bool array,
|
|
|
|
glsl_base_type type)
|
|
|
|
{
|
|
|
|
switch (type) {
|
|
|
|
case GLSL_TYPE_FLOAT:
|
|
|
|
switch (dim) {
|
|
|
|
case GLSL_SAMPLER_DIM_1D:
|
|
|
|
if (shadow)
|
|
|
|
return (array ? sampler1DArrayShadow_type : sampler1DShadow_type);
|
|
|
|
else
|
|
|
|
return (array ? sampler1DArray_type : sampler1D_type);
|
|
|
|
case GLSL_SAMPLER_DIM_2D:
|
|
|
|
if (shadow)
|
|
|
|
return (array ? sampler2DArrayShadow_type : sampler2DShadow_type);
|
|
|
|
else
|
|
|
|
return (array ? sampler2DArray_type : sampler2D_type);
|
|
|
|
case GLSL_SAMPLER_DIM_3D:
|
|
|
|
if (shadow || array)
|
|
|
|
return error_type;
|
|
|
|
else
|
|
|
|
return sampler3D_type;
|
|
|
|
case GLSL_SAMPLER_DIM_CUBE:
|
|
|
|
if (shadow)
|
|
|
|
return (array ? samplerCubeArrayShadow_type : samplerCubeShadow_type);
|
|
|
|
else
|
|
|
|
return (array ? samplerCubeArray_type : samplerCube_type);
|
|
|
|
case GLSL_SAMPLER_DIM_RECT:
|
|
|
|
if (array)
|
|
|
|
return error_type;
|
|
|
|
if (shadow)
|
|
|
|
return sampler2DRectShadow_type;
|
|
|
|
else
|
|
|
|
return sampler2DRect_type;
|
|
|
|
case GLSL_SAMPLER_DIM_BUF:
|
|
|
|
if (shadow || array)
|
|
|
|
return error_type;
|
|
|
|
else
|
|
|
|
return samplerBuffer_type;
|
|
|
|
case GLSL_SAMPLER_DIM_MS:
|
|
|
|
if (shadow)
|
|
|
|
return error_type;
|
|
|
|
return (array ? sampler2DMSArray_type : sampler2DMS_type);
|
|
|
|
case GLSL_SAMPLER_DIM_EXTERNAL:
|
|
|
|
if (shadow || array)
|
|
|
|
return error_type;
|
|
|
|
else
|
|
|
|
return samplerExternalOES_type;
|
|
|
|
}
|
|
|
|
case GLSL_TYPE_INT:
|
|
|
|
if (shadow)
|
|
|
|
return error_type;
|
|
|
|
switch (dim) {
|
|
|
|
case GLSL_SAMPLER_DIM_1D:
|
|
|
|
return (array ? isampler1DArray_type : isampler1D_type);
|
|
|
|
case GLSL_SAMPLER_DIM_2D:
|
|
|
|
return (array ? isampler2DArray_type : isampler2D_type);
|
|
|
|
case GLSL_SAMPLER_DIM_3D:
|
|
|
|
if (array)
|
|
|
|
return error_type;
|
|
|
|
return isampler3D_type;
|
|
|
|
case GLSL_SAMPLER_DIM_CUBE:
|
|
|
|
return (array ? isamplerCubeArray_type : isamplerCube_type);
|
|
|
|
case GLSL_SAMPLER_DIM_RECT:
|
|
|
|
if (array)
|
|
|
|
return error_type;
|
|
|
|
return isampler2DRect_type;
|
|
|
|
case GLSL_SAMPLER_DIM_BUF:
|
|
|
|
if (array)
|
|
|
|
return error_type;
|
|
|
|
return isamplerBuffer_type;
|
|
|
|
case GLSL_SAMPLER_DIM_MS:
|
|
|
|
return (array ? isampler2DMSArray_type : isampler2DMS_type);
|
|
|
|
case GLSL_SAMPLER_DIM_EXTERNAL:
|
|
|
|
return error_type;
|
|
|
|
}
|
|
|
|
case GLSL_TYPE_UINT:
|
|
|
|
if (shadow)
|
|
|
|
return error_type;
|
|
|
|
switch (dim) {
|
|
|
|
case GLSL_SAMPLER_DIM_1D:
|
|
|
|
return (array ? usampler1DArray_type : usampler1D_type);
|
|
|
|
case GLSL_SAMPLER_DIM_2D:
|
|
|
|
return (array ? usampler2DArray_type : usampler2D_type);
|
|
|
|
case GLSL_SAMPLER_DIM_3D:
|
|
|
|
if (array)
|
|
|
|
return error_type;
|
|
|
|
return usampler3D_type;
|
|
|
|
case GLSL_SAMPLER_DIM_CUBE:
|
|
|
|
return (array ? usamplerCubeArray_type : usamplerCube_type);
|
|
|
|
case GLSL_SAMPLER_DIM_RECT:
|
|
|
|
if (array)
|
|
|
|
return error_type;
|
|
|
|
return usampler2DRect_type;
|
|
|
|
case GLSL_SAMPLER_DIM_BUF:
|
|
|
|
if (array)
|
|
|
|
return error_type;
|
|
|
|
return usamplerBuffer_type;
|
|
|
|
case GLSL_SAMPLER_DIM_MS:
|
|
|
|
return (array ? usampler2DMSArray_type : usampler2DMS_type);
|
|
|
|
case GLSL_SAMPLER_DIM_EXTERNAL:
|
|
|
|
return error_type;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return error_type;
|
|
|
|
}
|
|
|
|
|
|
|
|
unreachable("switch statement above should be complete");
|
|
|
|
}
|
2010-03-31 00:58:19 +01:00
|
|
|
|
|
|
|
const glsl_type *
|
2010-07-20 23:33:40 +01:00
|
|
|
glsl_type::get_array_instance(const glsl_type *base, unsigned array_size)
|
2010-03-31 00:58:19 +01:00
|
|
|
{
|
2010-08-02 21:41:04 +01:00
|
|
|
/* 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
|
|
|
|
* named 'foo'.
|
|
|
|
*/
|
|
|
|
char key[128];
|
2010-08-11 21:04:51 +01:00
|
|
|
snprintf(key, sizeof(key), "%p[%u]", (void *) base, array_size);
|
2010-08-02 21:41:04 +01:00
|
|
|
|
2014-08-20 07:40:29 +01:00
|
|
|
mtx_lock(&glsl_type::mutex);
|
|
|
|
|
|
|
|
if (array_types == NULL) {
|
2015-07-13 22:37:59 +01:00
|
|
|
array_types = _mesa_hash_table_create(NULL, _mesa_key_hash_string,
|
|
|
|
_mesa_key_string_equal);
|
2014-08-20 07:40:29 +01:00
|
|
|
}
|
|
|
|
|
2015-07-13 22:37:59 +01:00
|
|
|
const struct hash_entry *entry = _mesa_hash_table_search(array_types, key);
|
|
|
|
if (entry == NULL) {
|
2014-08-20 07:40:29 +01:00
|
|
|
mtx_unlock(&glsl_type::mutex);
|
2015-07-13 22:37:59 +01:00
|
|
|
const glsl_type *t = new glsl_type(base, array_size);
|
2014-08-20 07:40:29 +01:00
|
|
|
mtx_lock(&glsl_type::mutex);
|
2010-03-31 00:58:19 +01:00
|
|
|
|
2015-07-13 22:37:59 +01:00
|
|
|
entry = _mesa_hash_table_insert(array_types,
|
|
|
|
ralloc_strdup(mem_ctx, key),
|
|
|
|
(void *) t);
|
2010-03-31 00:58:19 +01:00
|
|
|
}
|
|
|
|
|
2015-07-13 22:37:59 +01:00
|
|
|
assert(((glsl_type *) entry->data)->base_type == GLSL_TYPE_ARRAY);
|
|
|
|
assert(((glsl_type *) entry->data)->length == array_size);
|
|
|
|
assert(((glsl_type *) entry->data)->fields.array == base);
|
2010-03-31 00:58:19 +01:00
|
|
|
|
2014-08-20 07:40:29 +01:00
|
|
|
mtx_unlock(&glsl_type::mutex);
|
|
|
|
|
2015-07-13 22:37:59 +01:00
|
|
|
return (glsl_type *) entry->data;
|
2010-03-31 00:58:19 +01:00
|
|
|
}
|
2010-04-19 23:40:01 +01:00
|
|
|
|
|
|
|
|
2013-11-26 23:15:05 +00:00
|
|
|
bool
|
|
|
|
glsl_type::record_compare(const glsl_type *b) const
|
|
|
|
{
|
|
|
|
if (this->length != b->length)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (this->interface_packing != b->interface_packing)
|
|
|
|
return false;
|
|
|
|
|
2014-09-22 13:11:29 +01:00
|
|
|
/* 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;
|
|
|
|
|
2013-11-26 23:15:05 +00:00
|
|
|
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;
|
2014-07-17 00:51:14 +01:00
|
|
|
if (this->fields.structure[i].matrix_layout
|
|
|
|
!= b->fields.structure[i].matrix_layout)
|
2013-11-26 23:15:05 +00:00
|
|
|
return false;
|
|
|
|
if (this->fields.structure[i].location
|
|
|
|
!= b->fields.structure[i].location)
|
|
|
|
return false;
|
|
|
|
if (this->fields.structure[i].interpolation
|
|
|
|
!= b->fields.structure[i].interpolation)
|
|
|
|
return false;
|
|
|
|
if (this->fields.structure[i].centroid
|
|
|
|
!= b->fields.structure[i].centroid)
|
|
|
|
return false;
|
|
|
|
if (this->fields.structure[i].sample
|
|
|
|
!= b->fields.structure[i].sample)
|
|
|
|
return false;
|
2014-03-05 12:43:17 +00:00
|
|
|
if (this->fields.structure[i].patch
|
|
|
|
!= b->fields.structure[i].patch)
|
|
|
|
return false;
|
2013-11-26 23:15:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-07-13 22:37:59 +01:00
|
|
|
bool
|
2010-06-28 19:54:57 +01:00
|
|
|
glsl_type::record_key_compare(const void *a, const void *b)
|
|
|
|
{
|
|
|
|
const glsl_type *const key1 = (glsl_type *) a;
|
|
|
|
const glsl_type *const key2 = (glsl_type *) b;
|
|
|
|
|
2015-07-13 22:37:59 +01:00
|
|
|
return strcmp(key1->name, key2->name) == 0 && key1->record_compare(key2);
|
2010-06-28 19:54:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-04-16 22:29:18 +01:00
|
|
|
/**
|
|
|
|
* Generate an integer hash value for a glsl_type structure type.
|
|
|
|
*/
|
2010-06-28 19:54:57 +01:00
|
|
|
unsigned
|
|
|
|
glsl_type::record_key_hash(const void *a)
|
|
|
|
{
|
|
|
|
const glsl_type *const key = (glsl_type *) a;
|
2015-04-16 22:29:18 +01:00
|
|
|
uintptr_t hash = key->length;
|
|
|
|
unsigned retval;
|
2010-06-28 19:54:57 +01:00
|
|
|
|
|
|
|
for (unsigned i = 0; i < key->length; i++) {
|
2015-04-16 22:29:18 +01:00
|
|
|
/* casting pointer to uintptr_t */
|
|
|
|
hash = (hash * 13 ) + (uintptr_t) key->fields.structure[i].type;
|
2010-06-28 19:54:57 +01:00
|
|
|
}
|
|
|
|
|
2015-04-16 22:29:18 +01:00
|
|
|
if (sizeof(hash) == 8)
|
|
|
|
retval = (hash & 0xffffffff) ^ ((uint64_t) hash >> 32);
|
|
|
|
else
|
|
|
|
retval = hash;
|
|
|
|
|
|
|
|
return retval;
|
2010-06-28 19:54:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const glsl_type *
|
|
|
|
glsl_type::get_record_instance(const glsl_struct_field *fields,
|
|
|
|
unsigned num_fields,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
const glsl_type key(fields, num_fields, name);
|
|
|
|
|
2014-08-20 07:40:29 +01:00
|
|
|
mtx_lock(&glsl_type::mutex);
|
|
|
|
|
2010-06-28 19:54:57 +01:00
|
|
|
if (record_types == NULL) {
|
2015-07-13 22:37:59 +01:00
|
|
|
record_types = _mesa_hash_table_create(NULL, record_key_hash,
|
|
|
|
record_key_compare);
|
2010-06-28 19:54:57 +01:00
|
|
|
}
|
|
|
|
|
2015-07-13 22:37:59 +01:00
|
|
|
const struct hash_entry *entry = _mesa_hash_table_search(record_types,
|
|
|
|
&key);
|
|
|
|
if (entry == NULL) {
|
2014-08-20 07:40:29 +01:00
|
|
|
mtx_unlock(&glsl_type::mutex);
|
2015-07-13 22:37:59 +01:00
|
|
|
const glsl_type *t = new glsl_type(fields, num_fields, name);
|
2014-08-20 07:40:29 +01:00
|
|
|
mtx_lock(&glsl_type::mutex);
|
2010-06-28 19:54:57 +01:00
|
|
|
|
2015-07-13 22:37:59 +01:00
|
|
|
entry = _mesa_hash_table_insert(record_types, t, (void *) t);
|
2010-06-28 19:54:57 +01:00
|
|
|
}
|
|
|
|
|
2015-07-13 22:37:59 +01:00
|
|
|
assert(((glsl_type *) entry->data)->base_type == GLSL_TYPE_STRUCT);
|
|
|
|
assert(((glsl_type *) entry->data)->length == num_fields);
|
|
|
|
assert(strcmp(((glsl_type *) entry->data)->name, name) == 0);
|
2010-06-28 19:54:57 +01:00
|
|
|
|
2014-08-20 07:40:29 +01:00
|
|
|
mtx_unlock(&glsl_type::mutex);
|
|
|
|
|
2015-07-13 22:37:59 +01:00
|
|
|
return (glsl_type *) entry->data;
|
2010-06-28 19:54:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-12-11 20:11:16 +00:00
|
|
|
const glsl_type *
|
|
|
|
glsl_type::get_interface_instance(const glsl_struct_field *fields,
|
|
|
|
unsigned num_fields,
|
|
|
|
enum glsl_interface_packing packing,
|
2013-10-08 22:09:48 +01:00
|
|
|
const char *block_name)
|
2012-12-11 20:11:16 +00:00
|
|
|
{
|
2013-10-08 22:09:48 +01:00
|
|
|
const glsl_type key(fields, num_fields, packing, block_name);
|
2012-12-11 20:11:16 +00:00
|
|
|
|
2014-08-20 07:40:29 +01:00
|
|
|
mtx_lock(&glsl_type::mutex);
|
|
|
|
|
2012-12-11 20:11:16 +00:00
|
|
|
if (interface_types == NULL) {
|
2015-07-13 22:37:59 +01:00
|
|
|
interface_types = _mesa_hash_table_create(NULL, record_key_hash,
|
|
|
|
record_key_compare);
|
2012-12-11 20:11:16 +00:00
|
|
|
}
|
|
|
|
|
2015-07-13 22:37:59 +01:00
|
|
|
const struct hash_entry *entry = _mesa_hash_table_search(interface_types,
|
|
|
|
&key);
|
|
|
|
if (entry == NULL) {
|
2014-08-20 07:40:29 +01:00
|
|
|
mtx_unlock(&glsl_type::mutex);
|
2015-07-13 22:37:59 +01:00
|
|
|
const glsl_type *t = new glsl_type(fields, num_fields,
|
|
|
|
packing, block_name);
|
2014-08-20 07:40:29 +01:00
|
|
|
mtx_lock(&glsl_type::mutex);
|
2012-12-11 20:11:16 +00:00
|
|
|
|
2015-07-13 22:37:59 +01:00
|
|
|
entry = _mesa_hash_table_insert(interface_types, t, (void *) t);
|
2012-12-11 20:11:16 +00:00
|
|
|
}
|
|
|
|
|
2015-07-13 22:37:59 +01:00
|
|
|
assert(((glsl_type *) entry->data)->base_type == GLSL_TYPE_INTERFACE);
|
|
|
|
assert(((glsl_type *) entry->data)->length == num_fields);
|
|
|
|
assert(strcmp(((glsl_type *) entry->data)->name, block_name) == 0);
|
2012-12-11 20:11:16 +00:00
|
|
|
|
2014-08-20 07:40:29 +01:00
|
|
|
mtx_unlock(&glsl_type::mutex);
|
|
|
|
|
2015-07-13 22:37:59 +01:00
|
|
|
return (glsl_type *) entry->data;
|
2012-12-11 20:11:16 +00:00
|
|
|
}
|
|
|
|
|
2015-04-20 01:16:55 +01:00
|
|
|
const glsl_type *
|
|
|
|
glsl_type::get_subroutine_instance(const char *subroutine_name)
|
|
|
|
{
|
|
|
|
const glsl_type key(subroutine_name);
|
|
|
|
|
|
|
|
mtx_lock(&glsl_type::mutex);
|
|
|
|
|
|
|
|
if (subroutine_types == NULL) {
|
|
|
|
subroutine_types = _mesa_hash_table_create(NULL, record_key_hash,
|
|
|
|
record_key_compare);
|
|
|
|
}
|
|
|
|
|
|
|
|
const struct hash_entry *entry = _mesa_hash_table_search(subroutine_types,
|
|
|
|
&key);
|
|
|
|
if (entry == NULL) {
|
|
|
|
mtx_unlock(&glsl_type::mutex);
|
|
|
|
const glsl_type *t = new glsl_type(subroutine_name);
|
|
|
|
mtx_lock(&glsl_type::mutex);
|
|
|
|
|
|
|
|
entry = _mesa_hash_table_insert(subroutine_types, t, (void *) t);
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(((glsl_type *) entry->data)->base_type == GLSL_TYPE_SUBROUTINE);
|
|
|
|
assert(strcmp(((glsl_type *) entry->data)->name, subroutine_name) == 0);
|
|
|
|
|
|
|
|
mtx_unlock(&glsl_type::mutex);
|
|
|
|
|
|
|
|
return (glsl_type *) entry->data;
|
|
|
|
}
|
|
|
|
|
2012-12-11 20:11:16 +00:00
|
|
|
|
2015-03-27 17:43:05 +00:00
|
|
|
const glsl_type *
|
|
|
|
glsl_type::get_mul_type(const glsl_type *type_a, const glsl_type *type_b)
|
|
|
|
{
|
|
|
|
if (type_a == type_b) {
|
|
|
|
return type_a;
|
|
|
|
} else if (type_a->is_matrix() && type_b->is_matrix()) {
|
|
|
|
/* Matrix multiply. The columns of A must match the rows of B. Given
|
|
|
|
* the other previously tested constraints, this means the vector type
|
|
|
|
* of a row from A must be the same as the vector type of a column from
|
|
|
|
* B.
|
|
|
|
*/
|
|
|
|
if (type_a->row_type() == type_b->column_type()) {
|
|
|
|
/* The resulting matrix has the number of columns of matrix B and
|
|
|
|
* the number of rows of matrix A. We get the row count of A by
|
|
|
|
* looking at the size of a vector that makes up a column. The
|
|
|
|
* transpose (size of a row) is done for B.
|
|
|
|
*/
|
|
|
|
const glsl_type *const type =
|
|
|
|
get_instance(type_a->base_type,
|
|
|
|
type_a->column_type()->vector_elements,
|
|
|
|
type_b->row_type()->vector_elements);
|
|
|
|
assert(type != error_type);
|
|
|
|
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
} else if (type_a->is_matrix()) {
|
|
|
|
/* A is a matrix and B is a column vector. Columns of A must match
|
|
|
|
* rows of B. Given the other previously tested constraints, this
|
|
|
|
* means the vector type of a row from A must be the same as the
|
|
|
|
* vector the type of B.
|
|
|
|
*/
|
|
|
|
if (type_a->row_type() == type_b) {
|
|
|
|
/* The resulting vector has a number of elements equal to
|
|
|
|
* the number of rows of matrix A. */
|
|
|
|
const glsl_type *const type =
|
|
|
|
get_instance(type_a->base_type,
|
|
|
|
type_a->column_type()->vector_elements,
|
|
|
|
1);
|
|
|
|
assert(type != error_type);
|
|
|
|
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
assert(type_b->is_matrix());
|
|
|
|
|
|
|
|
/* A is a row vector and B is a matrix. Columns of A must match rows
|
|
|
|
* of B. Given the other previously tested constraints, this means
|
|
|
|
* the type of A must be the same as the vector type of a column from
|
|
|
|
* B.
|
|
|
|
*/
|
|
|
|
if (type_a == type_b->column_type()) {
|
|
|
|
/* The resulting vector has a number of elements equal to
|
|
|
|
* the number of columns of matrix B. */
|
|
|
|
const glsl_type *const type =
|
|
|
|
get_instance(type_a->base_type,
|
|
|
|
type_b->row_type()->vector_elements,
|
|
|
|
1);
|
|
|
|
assert(type != error_type);
|
|
|
|
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return error_type;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-04-19 23:40:01 +01:00
|
|
|
const glsl_type *
|
|
|
|
glsl_type::field_type(const char *name) const
|
|
|
|
{
|
2012-12-11 20:11:16 +00:00
|
|
|
if (this->base_type != GLSL_TYPE_STRUCT
|
|
|
|
&& this->base_type != GLSL_TYPE_INTERFACE)
|
2010-04-19 23:40:01 +01:00
|
|
|
return error_type;
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < this->length; i++) {
|
|
|
|
if (strcmp(name, this->fields.structure[i].name) == 0)
|
|
|
|
return this->fields.structure[i].type;
|
|
|
|
}
|
|
|
|
|
|
|
|
return error_type;
|
|
|
|
}
|
2010-06-10 01:27:31 +01:00
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
glsl_type::field_index(const char *name) const
|
|
|
|
{
|
2012-12-11 20:11:16 +00:00
|
|
|
if (this->base_type != GLSL_TYPE_STRUCT
|
|
|
|
&& this->base_type != GLSL_TYPE_INTERFACE)
|
2010-06-10 01:27:31 +01:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < this->length; i++) {
|
|
|
|
if (strcmp(name, this->fields.structure[i].name) == 0)
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
2010-06-22 00:05:00 +01:00
|
|
|
|
|
|
|
|
|
|
|
unsigned
|
|
|
|
glsl_type::component_slots() const
|
|
|
|
{
|
|
|
|
switch (this->base_type) {
|
|
|
|
case GLSL_TYPE_UINT:
|
|
|
|
case GLSL_TYPE_INT:
|
|
|
|
case GLSL_TYPE_FLOAT:
|
|
|
|
case GLSL_TYPE_BOOL:
|
|
|
|
return this->components();
|
|
|
|
|
2015-02-05 09:38:44 +00:00
|
|
|
case GLSL_TYPE_DOUBLE:
|
|
|
|
return 2 * this->components();
|
|
|
|
|
2012-12-11 20:11:16 +00:00
|
|
|
case GLSL_TYPE_STRUCT:
|
|
|
|
case GLSL_TYPE_INTERFACE: {
|
2010-06-22 00:05:00 +01:00
|
|
|
unsigned size = 0;
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < this->length; i++)
|
|
|
|
size += this->fields.structure[i].type->component_slots();
|
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
case GLSL_TYPE_ARRAY:
|
|
|
|
return this->length * this->fields.array->component_slots();
|
|
|
|
|
2013-11-25 21:50:47 +00:00
|
|
|
case GLSL_TYPE_IMAGE:
|
|
|
|
return 1;
|
2015-07-21 05:22:11 +01:00
|
|
|
case GLSL_TYPE_SUBROUTINE:
|
|
|
|
return 1;
|
2012-12-11 20:56:03 +00:00
|
|
|
case GLSL_TYPE_SAMPLER:
|
2013-10-20 20:35:47 +01:00
|
|
|
case GLSL_TYPE_ATOMIC_UINT:
|
2012-12-11 20:56:03 +00:00
|
|
|
case GLSL_TYPE_VOID:
|
|
|
|
case GLSL_TYPE_ERROR:
|
|
|
|
break;
|
2010-06-22 00:05:00 +01:00
|
|
|
}
|
2012-12-11 20:56:03 +00:00
|
|
|
|
|
|
|
return 0;
|
2010-06-22 00:05:00 +01:00
|
|
|
}
|
2011-07-27 20:21:27 +01:00
|
|
|
|
2015-09-11 22:33:27 +01:00
|
|
|
unsigned
|
|
|
|
glsl_type::record_location_offset(unsigned length) const
|
|
|
|
{
|
|
|
|
unsigned offset = 0;
|
|
|
|
const glsl_type *t = this->without_array();
|
|
|
|
if (t->is_record()) {
|
|
|
|
assert(length <= t->length);
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < length; i++) {
|
|
|
|
const glsl_type *st = t->fields.structure[i].type;
|
|
|
|
const glsl_type *wa = st->without_array();
|
|
|
|
if (wa->is_record()) {
|
|
|
|
unsigned r_offset = wa->record_location_offset(wa->length);
|
|
|
|
offset += st->is_array() ? st->length * r_offset : r_offset;
|
|
|
|
} else {
|
|
|
|
/* We dont worry about arrays here because unless the array
|
|
|
|
* contains a structure or another array it only takes up a single
|
|
|
|
* uniform slot.
|
|
|
|
*/
|
|
|
|
offset += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return offset;
|
|
|
|
}
|
|
|
|
|
2014-06-05 05:37:16 +01:00
|
|
|
unsigned
|
|
|
|
glsl_type::uniform_locations() const
|
|
|
|
{
|
|
|
|
unsigned size = 0;
|
|
|
|
|
|
|
|
switch (this->base_type) {
|
2014-08-27 12:12:27 +01:00
|
|
|
case GLSL_TYPE_UINT:
|
|
|
|
case GLSL_TYPE_INT:
|
|
|
|
case GLSL_TYPE_FLOAT:
|
2015-02-05 09:38:44 +00:00
|
|
|
case GLSL_TYPE_DOUBLE:
|
2014-08-27 12:12:27 +01:00
|
|
|
case GLSL_TYPE_BOOL:
|
|
|
|
case GLSL_TYPE_SAMPLER:
|
|
|
|
case GLSL_TYPE_IMAGE:
|
2015-04-20 01:16:55 +01:00
|
|
|
case GLSL_TYPE_SUBROUTINE:
|
2014-08-27 12:12:27 +01:00
|
|
|
return 1;
|
|
|
|
|
2014-06-05 05:37:16 +01:00
|
|
|
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:
|
2014-08-27 12:12:27 +01:00
|
|
|
return 0;
|
2014-06-05 05:37:16 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-27 20:21:27 +01:00
|
|
|
bool
|
2014-05-04 09:23:57 +01:00
|
|
|
glsl_type::can_implicitly_convert_to(const glsl_type *desired,
|
|
|
|
_mesa_glsl_parse_state *state) const
|
2011-07-27 20:21:27 +01:00
|
|
|
{
|
|
|
|
if (this == desired)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
/* There is no conversion among matrix types. */
|
|
|
|
if (this->matrix_columns > 1 || desired->matrix_columns > 1)
|
|
|
|
return false;
|
|
|
|
|
2014-05-04 09:23:58 +01:00
|
|
|
/* Vector size must match. */
|
|
|
|
if (this->vector_elements != desired->vector_elements)
|
|
|
|
return false;
|
|
|
|
|
2011-07-27 20:21:27 +01:00
|
|
|
/* int and uint can be converted to float. */
|
2014-05-04 09:23:58 +01:00
|
|
|
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;
|
|
|
|
|
2015-02-05 09:38:44 +00:00
|
|
|
/* No implicit conversions from double. */
|
|
|
|
if ((!state || state->has_double()) && this->is_double())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Conversions from different types to double. */
|
|
|
|
if ((!state || state->has_double()) && desired->is_double()) {
|
|
|
|
if (this->is_float())
|
|
|
|
return true;
|
|
|
|
if (this->is_integer())
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-05-04 09:23:58 +01:00
|
|
|
return false;
|
2011-07-27 20:21:27 +01:00
|
|
|
}
|
2012-05-01 23:10:14 +01:00
|
|
|
|
|
|
|
unsigned
|
|
|
|
glsl_type::std140_base_alignment(bool row_major) const
|
|
|
|
{
|
2015-02-05 09:38:44 +00:00
|
|
|
unsigned N = is_double() ? 8 : 4;
|
|
|
|
|
2012-05-01 23:10:14 +01:00
|
|
|
/* (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:
|
2015-02-05 09:38:44 +00:00
|
|
|
return N;
|
2012-05-01 23:10:14 +01:00
|
|
|
case 2:
|
2015-02-05 09:38:44 +00:00
|
|
|
return 2 * N;
|
2012-05-01 23:10:14 +01:00
|
|
|
case 3:
|
|
|
|
case 4:
|
2015-02-05 09:38:44 +00:00
|
|
|
return 4 * N;
|
2012-05-01 23:10:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* (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 {
|
2015-02-22 12:35:43 +00:00
|
|
|
assert(this->fields.array->is_record() ||
|
|
|
|
this->fields.array->is_array());
|
2012-05-01 23:10:14 +01:00
|
|
|
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()) {
|
2012-07-23 22:11:38 +01:00
|
|
|
const struct glsl_type *vec_type, *array_type;
|
|
|
|
int c = this->matrix_columns;
|
|
|
|
int r = this->vector_elements;
|
|
|
|
|
2012-05-01 23:10:14 +01:00
|
|
|
if (row_major) {
|
2015-02-05 09:38:44 +00:00
|
|
|
vec_type = get_instance(base_type, c, 1);
|
2012-07-23 22:11:38 +01:00
|
|
|
array_type = glsl_type::get_array_instance(vec_type, r);
|
2012-05-01 23:10:14 +01:00
|
|
|
} else {
|
2015-02-05 09:38:44 +00:00
|
|
|
vec_type = get_instance(base_type, r, 1);
|
2012-07-23 22:11:38 +01:00
|
|
|
array_type = glsl_type::get_array_instance(vec_type, c);
|
2012-05-01 23:10:14 +01:00
|
|
|
}
|
|
|
|
|
2012-07-23 22:11:38 +01:00
|
|
|
return array_type->std140_base_alignment(false);
|
2012-05-01 23:10:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* (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++) {
|
2014-07-17 00:51:14 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-05-01 23:10:14 +01:00
|
|
|
const struct glsl_type *field_type = this->fields.structure[i].type;
|
|
|
|
base_alignment = MAX2(base_alignment,
|
2014-07-17 00:51:14 +01:00
|
|
|
field_type->std140_base_alignment(field_row_major));
|
2012-05-01 23:10:14 +01:00
|
|
|
}
|
|
|
|
return base_alignment;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(!"not reached");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned
|
|
|
|
glsl_type::std140_size(bool row_major) const
|
|
|
|
{
|
2015-02-05 09:38:44 +00:00
|
|
|
unsigned N = is_double() ? 8 : 4;
|
|
|
|
|
2012-05-01 23:10:14 +01:00
|
|
|
/* (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()) {
|
2015-02-05 09:38:44 +00:00
|
|
|
return this->vector_elements * N;
|
2012-05-01 23:10:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* (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).
|
|
|
|
*/
|
2014-07-19 22:41:04 +01:00
|
|
|
if (this->without_array()->is_matrix()) {
|
2012-05-01 23:10:14 +01:00
|
|
|
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) {
|
2015-02-05 09:38:44 +00:00
|
|
|
vec_type = get_instance(element_type->base_type,
|
|
|
|
element_type->matrix_columns, 1);
|
|
|
|
|
2012-05-01 23:10:14 +01:00
|
|
|
array_len *= element_type->vector_elements;
|
|
|
|
} else {
|
2015-02-05 09:38:44 +00:00
|
|
|
vec_type = get_instance(element_type->base_type,
|
2012-05-01 23:10:14 +01:00
|
|
|
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;
|
2014-07-16 23:40:32 +01:00
|
|
|
unsigned max_align = 0;
|
|
|
|
|
2012-05-01 23:10:14 +01:00
|
|
|
for (unsigned i = 0; i < this->length; i++) {
|
2014-07-17 00:51:14 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-05-01 23:10:14 +01:00
|
|
|
const struct glsl_type *field_type = this->fields.structure[i].type;
|
2014-07-17 00:51:14 +01:00
|
|
|
unsigned align = field_type->std140_base_alignment(field_row_major);
|
2013-01-22 05:06:10 +00:00
|
|
|
size = glsl_align(size, align);
|
2014-07-17 00:51:14 +01:00
|
|
|
size += field_type->std140_size(field_row_major);
|
2014-07-16 23:40:32 +01:00
|
|
|
|
|
|
|
max_align = MAX2(align, max_align);
|
|
|
|
|
|
|
|
if (field_type->is_record() && (i + 1 < this->length))
|
|
|
|
size = glsl_align(size, 16);
|
2012-05-01 23:10:14 +01:00
|
|
|
}
|
2014-09-10 18:54:55 +01:00
|
|
|
size = glsl_align(size, MAX2(max_align, 16));
|
2012-05-01 23:10:14 +01:00
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(!"not reached");
|
|
|
|
return -1;
|
|
|
|
}
|
2013-07-31 16:15:08 +01:00
|
|
|
|
|
|
|
|
|
|
|
unsigned
|
|
|
|
glsl_type::count_attribute_slots() const
|
|
|
|
{
|
|
|
|
/* From page 31 (page 37 of the PDF) of the GLSL 1.50 spec:
|
|
|
|
*
|
|
|
|
* "A scalar input counts the same amount against this limit as a vec4,
|
|
|
|
* so applications may want to consider packing groups of four
|
|
|
|
* unrelated float inputs together into a vector to better utilize the
|
|
|
|
* capabilities of the underlying hardware. A matrix input will use up
|
|
|
|
* multiple locations. The number of locations used will equal the
|
|
|
|
* number of columns in the matrix."
|
|
|
|
*
|
|
|
|
* The spec does not explicitly say how arrays are counted. However, it
|
|
|
|
* should be safe to assume the total number of slots consumed by an array
|
|
|
|
* is the number of entries in the array multiplied by the number of slots
|
|
|
|
* consumed by a single element of the array.
|
2013-07-31 16:24:48 +01:00
|
|
|
*
|
|
|
|
* The spec says nothing about how structs are counted, because vertex
|
|
|
|
* attributes are not allowed to be (or contain) structs. However, Mesa
|
|
|
|
* allows varying structs, the number of varying slots taken up by a
|
|
|
|
* varying struct is simply equal to the sum of the number of slots taken
|
|
|
|
* up by each element.
|
2013-07-31 16:15:08 +01:00
|
|
|
*/
|
2013-07-31 16:24:48 +01:00
|
|
|
switch (this->base_type) {
|
|
|
|
case GLSL_TYPE_UINT:
|
|
|
|
case GLSL_TYPE_INT:
|
|
|
|
case GLSL_TYPE_FLOAT:
|
|
|
|
case GLSL_TYPE_BOOL:
|
2015-02-05 09:38:44 +00:00
|
|
|
case GLSL_TYPE_DOUBLE:
|
2013-07-31 16:24:48 +01:00
|
|
|
return this->matrix_columns;
|
2013-07-31 16:15:08 +01:00
|
|
|
|
2013-07-31 16:24:48 +01:00
|
|
|
case GLSL_TYPE_STRUCT:
|
|
|
|
case GLSL_TYPE_INTERFACE: {
|
|
|
|
unsigned size = 0;
|
2013-07-31 16:15:08 +01:00
|
|
|
|
2013-07-31 16:24:48 +01:00
|
|
|
for (unsigned i = 0; i < this->length; i++)
|
|
|
|
size += this->fields.structure[i].type->count_attribute_slots();
|
2013-07-31 16:15:08 +01:00
|
|
|
|
2013-07-31 16:24:48 +01:00
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
case GLSL_TYPE_ARRAY:
|
|
|
|
return this->length * this->fields.array->count_attribute_slots();
|
|
|
|
|
|
|
|
case GLSL_TYPE_SAMPLER:
|
2013-11-25 21:50:47 +00:00
|
|
|
case GLSL_TYPE_IMAGE:
|
2013-10-20 20:35:47 +01:00
|
|
|
case GLSL_TYPE_ATOMIC_UINT:
|
2013-07-31 16:24:48 +01:00
|
|
|
case GLSL_TYPE_VOID:
|
2015-04-20 01:16:55 +01:00
|
|
|
case GLSL_TYPE_SUBROUTINE:
|
2013-07-31 16:24:48 +01:00
|
|
|
case GLSL_TYPE_ERROR:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(!"Unexpected type in count_attribute_slots()");
|
|
|
|
|
|
|
|
return 0;
|
2013-07-31 16:15:08 +01:00
|
|
|
}
|
2013-09-11 19:14:14 +01:00
|
|
|
|
|
|
|
int
|
2013-11-25 22:03:06 +00:00
|
|
|
glsl_type::coordinate_components() const
|
2013-09-11 19:14:14 +01:00
|
|
|
{
|
|
|
|
int size;
|
|
|
|
|
|
|
|
switch (sampler_dimensionality) {
|
|
|
|
case GLSL_SAMPLER_DIM_1D:
|
|
|
|
case GLSL_SAMPLER_DIM_BUF:
|
|
|
|
size = 1;
|
|
|
|
break;
|
|
|
|
case GLSL_SAMPLER_DIM_2D:
|
|
|
|
case GLSL_SAMPLER_DIM_RECT:
|
|
|
|
case GLSL_SAMPLER_DIM_MS:
|
|
|
|
case GLSL_SAMPLER_DIM_EXTERNAL:
|
|
|
|
size = 2;
|
|
|
|
break;
|
|
|
|
case GLSL_SAMPLER_DIM_3D:
|
|
|
|
case GLSL_SAMPLER_DIM_CUBE:
|
|
|
|
size = 3;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
assert(!"Should not get here.");
|
|
|
|
size = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-11-19 16:22:07 +00:00
|
|
|
/* Array textures need an additional component for the array index, except
|
|
|
|
* for cubemap array images that behave like a 2D array of interleaved
|
|
|
|
* cubemap faces.
|
|
|
|
*/
|
|
|
|
if (sampler_array &&
|
|
|
|
!(base_type == GLSL_TYPE_IMAGE &&
|
|
|
|
sampler_dimensionality == GLSL_SAMPLER_DIM_CUBE))
|
2013-09-11 19:14:14 +01:00
|
|
|
size += 1;
|
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|