blob: b2f0f149956c7deb1059b447557a9b57da5ceb57 [file] [log] [blame]
/*
* Mesa 3-D graphics library
* Version: 6.5
*
* Copyright (C) 2005-2006 Brian Paul All Rights Reserved.
*
* 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 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
* BRIAN PAUL 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.
*/
/**
* \file slang_assemble_typeinfo.c
* slang type info
* \author Michal Krol
*/
#include "main/imports.h"
#include "shader/prog_instruction.h"
#include "slang_typeinfo.h"
#include "slang_compile.h"
#include "slang_log.h"
#include "slang_mem.h"
/**
* Checks if a field selector is a general swizzle (an r-value swizzle
* with replicated components or an l-value swizzle mask) for a
* vector. Returns GL_TRUE if this is the case, <swz> is filled with
* swizzle information. Returns GL_FALSE otherwise.
*/
GLboolean
_slang_is_swizzle(const char *field, GLuint rows, slang_swizzle * swz)
{
GLuint i;
GLboolean xyzw = GL_FALSE, rgba = GL_FALSE, stpq = GL_FALSE;
/* init to undefined.
* We rely on undefined/nil values to distinguish between
* regular swizzles and writemasks.
* For example, the swizzle ".xNNN" is the writemask ".x".
* That's different than the swizzle ".xxxx".
*/
for (i = 0; i < 4; i++)
swz->swizzle[i] = SWIZZLE_NIL;
/* the swizzle can be at most 4-component long */
swz->num_components = slang_string_length(field);
if (swz->num_components > 4)
return GL_FALSE;
for (i = 0; i < swz->num_components; i++) {
/* mark which swizzle group is used */
switch (field[i]) {
case 'x':
case 'y':
case 'z':
case 'w':
xyzw = GL_TRUE;
break;
case 'r':
case 'g':
case 'b':
case 'a':
rgba = GL_TRUE;
break;
case 's':
case 't':
case 'p':
case 'q':
stpq = GL_TRUE;
break;
default:
return GL_FALSE;
}
/* collect swizzle component */
switch (field[i]) {
case 'x':
case 'r':
case 's':
swz->swizzle[i] = 0;
break;
case 'y':
case 'g':
case 't':
swz->swizzle[i] = 1;
break;
case 'z':
case 'b':
case 'p':
swz->swizzle[i] = 2;
break;
case 'w':
case 'a':
case 'q':
swz->swizzle[i] = 3;
break;
}
/* check if the component is valid for given vector's row count */
if (rows <= swz->swizzle[i])
return GL_FALSE;
}
/* only one swizzle group can be used */
if ((xyzw && rgba) || (xyzw && stpq) || (rgba && stpq))
return GL_FALSE;
return GL_TRUE;
}
/**
* Checks if a general swizzle is an l-value swizzle - these swizzles
* do not have duplicated fields. Returns GL_TRUE if this is a
* swizzle mask. Returns GL_FALSE otherwise
*/
GLboolean
_slang_is_swizzle_mask(const slang_swizzle * swz, GLuint rows)
{
GLuint i, c = 0;
/* the swizzle may not be longer than the vector dim */
if (swz->num_components > rows)
return GL_FALSE;
/* the swizzle components cannot be duplicated */
for (i = 0; i < swz->num_components; i++) {
if ((c & (1 << swz->swizzle[i])) != 0)
return GL_FALSE;
c |= 1 << swz->swizzle[i];
}
return GL_TRUE;
}
/**
* Combines (multiplies) two swizzles to form single swizzle.
* Example: "vec.wzyx.yx" --> "vec.zw".
*/
GLvoid
_slang_multiply_swizzles(slang_swizzle * dst, const slang_swizzle * left,
const slang_swizzle * right)
{
GLuint i;
dst->num_components = right->num_components;
for (i = 0; i < right->num_components; i++)
dst->swizzle[i] = left->swizzle[right->swizzle[i]];
}
GLvoid
slang_type_specifier_ctr(slang_type_specifier * self)
{
self->type = SLANG_SPEC_VOID;
self->_struct = NULL;
self->_array = NULL;
}
GLvoid
slang_type_specifier_dtr(slang_type_specifier * self)
{
if (self->_struct != NULL) {
slang_struct_destruct(self->_struct);
_slang_free(self->_struct);
}
if (self->_array != NULL) {
slang_type_specifier_dtr(self->_array);
_slang_free(self->_array);
}
}
GLboolean
slang_type_specifier_copy(slang_type_specifier * x,
const slang_type_specifier * y)
{
slang_type_specifier z;
slang_type_specifier_ctr(&z);
z.type = y->type;
if (z.type == SLANG_SPEC_STRUCT) {
z._struct = (slang_struct *) _slang_alloc(sizeof(slang_struct));
if (z._struct == NULL) {
slang_type_specifier_dtr(&z);
return GL_FALSE;
}
if (!slang_struct_construct(z._struct)) {
_slang_free(z._struct);
slang_type_specifier_dtr(&z);
return GL_FALSE;
}
if (!slang_struct_copy(z._struct, y->_struct)) {
slang_type_specifier_dtr(&z);
return GL_FALSE;
}
}
else if (z.type == SLANG_SPEC_ARRAY) {
z._array = (slang_type_specifier *)
_slang_alloc(sizeof(slang_type_specifier));
if (z._array == NULL) {
slang_type_specifier_dtr(&z);
return GL_FALSE;
}
slang_type_specifier_ctr(z._array);
if (!slang_type_specifier_copy(z._array, y->_array)) {
slang_type_specifier_dtr(&z);
return GL_FALSE;
}
}
slang_type_specifier_dtr(x);
*x = z;
return GL_TRUE;
}
/**
* Test if two types are equal.
*/
GLboolean
slang_type_specifier_equal(const slang_type_specifier * x,
const slang_type_specifier * y)
{
if (x->type != y->type)
return GL_FALSE;
if (x->type == SLANG_SPEC_STRUCT)
return slang_struct_equal(x->_struct, y->_struct);
if (x->type == SLANG_SPEC_ARRAY)
return slang_type_specifier_equal(x->_array, y->_array);
return GL_TRUE;
}
/**
* As above, but allow float/int casting.
*/
static GLboolean
slang_type_specifier_compatible(const slang_type_specifier * x,
const slang_type_specifier * y)
{
/* special case: float == int */
if (x->type == SLANG_SPEC_INT && y->type == SLANG_SPEC_FLOAT) {
return GL_TRUE;
}
/* XXX may need to add bool/int compatibility, etc */
if (x->type != y->type)
return GL_FALSE;
if (x->type == SLANG_SPEC_STRUCT)
return slang_struct_equal(x->_struct, y->_struct);
if (x->type == SLANG_SPEC_ARRAY)
return slang_type_specifier_compatible(x->_array, y->_array);
return GL_TRUE;
}
GLboolean
slang_typeinfo_construct(slang_typeinfo * ti)
{
_mesa_bzero(ti, sizeof(*ti));
slang_type_specifier_ctr(&ti->spec);
ti->array_len = 0;
return GL_TRUE;
}
GLvoid
slang_typeinfo_destruct(slang_typeinfo * ti)
{
slang_type_specifier_dtr(&ti->spec);
}
/**
* Determine the return type of a function.
* \param a_name the function name
* \param param function parameters (overloading)
* \param num_params number of parameters to function
* \param space namespace to search
* \param spec returns the type
* \param funFound returns pointer to the function, or NULL if not found.
* \return GL_TRUE for success, GL_FALSE if failure (bad function name)
*/
static GLboolean
_slang_typeof_function(slang_atom a_name,
slang_operation * params, GLuint num_params,
const slang_name_space * space,
slang_type_specifier * spec,
slang_function **funFound,
slang_atom_pool *atoms, slang_info_log *log)
{
GLboolean error;
*funFound = _slang_locate_function(space->funcs, a_name, params,
num_params, space, atoms, log, &error);
if (error)
return GL_FALSE;
if (!*funFound)
return GL_TRUE; /* yes, not false */
return slang_type_specifier_copy(spec, &(*funFound)->header.type.specifier);
}
/**
* Determine the type of a math function.
* \param name name of the operator, one of +,-,*,/ or unary -
* \param params array of function parameters
* \param num_params number of parameters
* \param space namespace to use
* \param spec returns the function's type
* \param atoms atom pool
* \return GL_TRUE for success, GL_FALSE if failure
*/
static GLboolean
typeof_math_call(const char *name, slang_operation *call,
const slang_name_space * space,
slang_type_specifier * spec,
slang_atom_pool * atoms,
slang_info_log *log)
{
if (call->fun) {
/* we've previously resolved this function call */
slang_type_specifier_copy(spec, &call->fun->header.type.specifier);
return GL_TRUE;
}
else {
slang_atom atom;
slang_function *fun;
/* number of params: */
assert(call->num_children == 1 || call->num_children == 2);
atom = slang_atom_pool_atom(atoms, name);
if (!_slang_typeof_function(atom, call->children, call->num_children,
space, spec, &fun, atoms, log))
return GL_FALSE;
if (fun) {
/* Save pointer to save time in future */
call->fun = fun;
return GL_TRUE;
}
return GL_FALSE;
}
}
GLboolean
_slang_typeof_operation(const slang_assemble_ctx * A,
slang_operation * op,
slang_typeinfo * ti)
{
return _slang_typeof_operation_(op, &A->space, ti, A->atoms, A->log);
}
/**
* Determine the return type of an operation.
* \param op the operation node
* \param space the namespace to use
* \param ti the returned type
* \param atoms atom pool
* \return GL_TRUE for success, GL_FALSE if failure
*/
GLboolean
_slang_typeof_operation_(slang_operation * op,
const slang_name_space * space,
slang_typeinfo * ti,
slang_atom_pool * atoms,
slang_info_log *log)
{
ti->can_be_referenced = GL_FALSE;
ti->is_swizzled = GL_FALSE;
switch (op->type) {
case SLANG_OPER_BLOCK_NO_NEW_SCOPE:
case SLANG_OPER_BLOCK_NEW_SCOPE:
case SLANG_OPER_ASM:
case SLANG_OPER_BREAK:
case SLANG_OPER_CONTINUE:
case SLANG_OPER_DISCARD:
case SLANG_OPER_RETURN:
case SLANG_OPER_IF:
case SLANG_OPER_WHILE:
case SLANG_OPER_DO:
case SLANG_OPER_FOR:
case SLANG_OPER_VOID:
ti->spec.type = SLANG_SPEC_VOID;
break;
case SLANG_OPER_EXPRESSION:
case SLANG_OPER_ASSIGN:
case SLANG_OPER_ADDASSIGN:
case SLANG_OPER_SUBASSIGN:
case SLANG_OPER_MULASSIGN:
case SLANG_OPER_DIVASSIGN:
case SLANG_OPER_PREINCREMENT:
case SLANG_OPER_PREDECREMENT:
if (!_slang_typeof_operation_(op->children, space, ti, atoms, log))
return GL_FALSE;
break;
case SLANG_OPER_LITERAL_BOOL:
if (op->literal_size == 1)
ti->spec.type = SLANG_SPEC_BOOL;
else if (op->literal_size == 2)
ti->spec.type = SLANG_SPEC_BVEC2;
else if (op->literal_size == 3)
ti->spec.type = SLANG_SPEC_BVEC3;
else if (op->literal_size == 4)
ti->spec.type = SLANG_SPEC_BVEC4;
else {
_mesa_problem(NULL,
"Unexpected bool literal_size %d in _slang_typeof_operation()",
op->literal_size);
ti->spec.type = SLANG_SPEC_BOOL;
}
break;
case SLANG_OPER_LOGICALOR:
case SLANG_OPER_LOGICALXOR:
case SLANG_OPER_LOGICALAND:
case SLANG_OPER_EQUAL:
case SLANG_OPER_NOTEQUAL:
case SLANG_OPER_LESS:
case SLANG_OPER_GREATER:
case SLANG_OPER_LESSEQUAL:
case SLANG_OPER_GREATEREQUAL:
case SLANG_OPER_NOT:
ti->spec.type = SLANG_SPEC_BOOL;
break;
case SLANG_OPER_LITERAL_INT:
if (op->literal_size == 1)
ti->spec.type = SLANG_SPEC_INT;
else if (op->literal_size == 2)
ti->spec.type = SLANG_SPEC_IVEC2;
else if (op->literal_size == 3)
ti->spec.type = SLANG_SPEC_IVEC3;
else if (op->literal_size == 4)
ti->spec.type = SLANG_SPEC_IVEC4;
else {
_mesa_problem(NULL,
"Unexpected int literal_size %d in _slang_typeof_operation()",
op->literal_size);
ti->spec.type = SLANG_SPEC_INT;
}
break;
case SLANG_OPER_LITERAL_FLOAT:
if (op->literal_size == 1)
ti->spec.type = SLANG_SPEC_FLOAT;
else if (op->literal_size == 2)
ti->spec.type = SLANG_SPEC_VEC2;
else if (op->literal_size == 3)
ti->spec.type = SLANG_SPEC_VEC3;
else if (op->literal_size == 4)
ti->spec.type = SLANG_SPEC_VEC4;
else {
_mesa_problem(NULL,
"Unexpected float literal_size %d in _slang_typeof_operation()",
op->literal_size);
ti->spec.type = SLANG_SPEC_FLOAT;
}
break;
case SLANG_OPER_IDENTIFIER:
case SLANG_OPER_VARIABLE_DECL:
{
slang_variable *var;
var = _slang_locate_variable(op->locals, op->a_id, GL_TRUE);
if (!var) {
slang_info_log_error(log, "undefined variable '%s'",
(char *) op->a_id);
return GL_FALSE;
}
if (!slang_type_specifier_copy(&ti->spec, &var->type.specifier)) {
slang_info_log_memory(log);
return GL_FALSE;
}
ti->can_be_referenced = GL_TRUE;
ti->array_len = var->array_len;
}
break;
case SLANG_OPER_SEQUENCE:
/* TODO: check [0] and [1] if they match */
if (!_slang_typeof_operation_(&op->children[1], space, ti, atoms, log)) {
return GL_FALSE;
}
ti->can_be_referenced = GL_FALSE;
ti->is_swizzled = GL_FALSE;
break;
/*case SLANG_OPER_MODASSIGN: */
/*case SLANG_OPER_LSHASSIGN: */
/*case SLANG_OPER_RSHASSIGN: */
/*case SLANG_OPER_ORASSIGN: */
/*case SLANG_OPER_XORASSIGN: */
/*case SLANG_OPER_ANDASSIGN: */
case SLANG_OPER_SELECT:
/* TODO: check [1] and [2] if they match */
if (!_slang_typeof_operation_(&op->children[1], space, ti, atoms, log)) {
return GL_FALSE;
}
ti->can_be_referenced = GL_FALSE;
ti->is_swizzled = GL_FALSE;
break;
/*case SLANG_OPER_BITOR: */
/*case SLANG_OPER_BITXOR: */
/*case SLANG_OPER_BITAND: */
/*case SLANG_OPER_LSHIFT: */
/*case SLANG_OPER_RSHIFT: */
case SLANG_OPER_ADD:
assert(op->num_children == 2);
if (!typeof_math_call("+", op, space, &ti->spec, atoms, log))
return GL_FALSE;
break;
case SLANG_OPER_SUBTRACT:
assert(op->num_children == 2);
if (!typeof_math_call("-", op, space, &ti->spec, atoms, log))
return GL_FALSE;
break;
case SLANG_OPER_MULTIPLY:
assert(op->num_children == 2);
if (!typeof_math_call("*", op, space, &ti->spec, atoms, log))
return GL_FALSE;
break;
case SLANG_OPER_DIVIDE:
assert(op->num_children == 2);
if (!typeof_math_call("/", op, space, &ti->spec, atoms, log))
return GL_FALSE;
break;
/*case SLANG_OPER_MODULUS: */
case SLANG_OPER_PLUS:
if (!_slang_typeof_operation_(op->children, space, ti, atoms, log))
return GL_FALSE;
ti->can_be_referenced = GL_FALSE;
ti->is_swizzled = GL_FALSE;
break;
case SLANG_OPER_MINUS:
assert(op->num_children == 1);
if (!typeof_math_call("-", op, space, &ti->spec, atoms, log))
return GL_FALSE;
break;
/*case SLANG_OPER_COMPLEMENT: */
case SLANG_OPER_SUBSCRIPT:
{
slang_typeinfo _ti;
if (!slang_typeinfo_construct(&_ti))
return GL_FALSE;
if (!_slang_typeof_operation_(op->children, space, &_ti, atoms, log)) {
slang_typeinfo_destruct(&_ti);
return GL_FALSE;
}
ti->can_be_referenced = _ti.can_be_referenced;
if (_ti.spec.type == SLANG_SPEC_ARRAY) {
if (!slang_type_specifier_copy(&ti->spec, _ti.spec._array)) {
slang_typeinfo_destruct(&_ti);
return GL_FALSE;
}
}
else {
if (!_slang_type_is_vector(_ti.spec.type)
&& !_slang_type_is_matrix(_ti.spec.type)) {
slang_typeinfo_destruct(&_ti);
slang_info_log_error(log, "cannot index a non-array type");
return GL_FALSE;
}
ti->spec.type = _slang_type_base(_ti.spec.type);
}
slang_typeinfo_destruct(&_ti);
}
break;
case SLANG_OPER_CALL:
if (op->fun) {
/* we've resolved this call before */
slang_type_specifier_copy(&ti->spec, &op->fun->header.type.specifier);
}
else {
slang_function *fun;
if (!_slang_typeof_function(op->a_id, op->children, op->num_children,
space, &ti->spec, &fun, atoms, log))
return GL_FALSE;
if (fun) {
/* save result for future use */
op->fun = fun;
}
else {
slang_struct *s =
slang_struct_scope_find(space->structs, op->a_id, GL_TRUE);
if (s) {
/* struct initializer */
ti->spec.type = SLANG_SPEC_STRUCT;
ti->spec._struct =
(slang_struct *) _slang_alloc(sizeof(slang_struct));
if (ti->spec._struct == NULL)
return GL_FALSE;
if (!slang_struct_construct(ti->spec._struct)) {
_slang_free(ti->spec._struct);
ti->spec._struct = NULL;
return GL_FALSE;
}
if (!slang_struct_copy(ti->spec._struct, s))
return GL_FALSE;
}
else {
/* float, int, vec4, mat3, etc. constructor? */
const char *name;
slang_type_specifier_type type;
name = slang_atom_pool_id(atoms, op->a_id);
type = slang_type_specifier_type_from_string(name);
if (type == SLANG_SPEC_VOID) {
slang_info_log_error(log, "undefined function '%s'", name);
return GL_FALSE;
}
ti->spec.type = type;
}
}
}
break;
case SLANG_OPER_FIELD:
{
slang_typeinfo _ti;
if (!slang_typeinfo_construct(&_ti))
return GL_FALSE;
if (!_slang_typeof_operation_(op->children, space, &_ti, atoms, log)) {
slang_typeinfo_destruct(&_ti);
return GL_FALSE;
}
if (_ti.spec.type == SLANG_SPEC_STRUCT) {
slang_variable *field;
field = _slang_locate_variable(_ti.spec._struct->fields, op->a_id,
GL_FALSE);
if (field == NULL) {
slang_typeinfo_destruct(&_ti);
return GL_FALSE;
}
if (!slang_type_specifier_copy(&ti->spec, &field->type.specifier)) {
slang_typeinfo_destruct(&_ti);
return GL_FALSE;
}
ti->can_be_referenced = _ti.can_be_referenced;
}
else {
GLuint rows;
const char *swizzle;
slang_type_specifier_type base;
/* determine the swizzle of the field expression */
if (!_slang_type_is_vector(_ti.spec.type)) {
slang_typeinfo_destruct(&_ti);
slang_info_log_error(log, "Can't swizzle scalar expression");
return GL_FALSE;
}
rows = _slang_type_dim(_ti.spec.type);
swizzle = slang_atom_pool_id(atoms, op->a_id);
if (!_slang_is_swizzle(swizzle, rows, &ti->swz)) {
slang_typeinfo_destruct(&_ti);
slang_info_log_error(log, "bad swizzle '%s'", swizzle);
return GL_FALSE;
}
ti->is_swizzled = GL_TRUE;
ti->can_be_referenced = _ti.can_be_referenced
&& _slang_is_swizzle_mask(&ti->swz, rows);
if (_ti.is_swizzled) {
slang_swizzle swz;
/* swizzle the swizzle */
_slang_multiply_swizzles(&swz, &_ti.swz, &ti->swz);
ti->swz = swz;
}
base = _slang_type_base(_ti.spec.type);
switch (ti->swz.num_components) {
case 1:
ti->spec.type = base;
break;
case 2:
switch (base) {
case SLANG_SPEC_FLOAT:
ti->spec.type = SLANG_SPEC_VEC2;
break;
case SLANG_SPEC_INT:
ti->spec.type = SLANG_SPEC_IVEC2;
break;
case SLANG_SPEC_BOOL:
ti->spec.type = SLANG_SPEC_BVEC2;
break;
default:
break;
}
break;
case 3:
switch (base) {
case SLANG_SPEC_FLOAT:
ti->spec.type = SLANG_SPEC_VEC3;
break;
case SLANG_SPEC_INT:
ti->spec.type = SLANG_SPEC_IVEC3;
break;
case SLANG_SPEC_BOOL:
ti->spec.type = SLANG_SPEC_BVEC3;
break;
default:
break;
}
break;
case 4:
switch (base) {
case SLANG_SPEC_FLOAT:
ti->spec.type = SLANG_SPEC_VEC4;
break;
case SLANG_SPEC_INT:
ti->spec.type = SLANG_SPEC_IVEC4;
break;
case SLANG_SPEC_BOOL:
ti->spec.type = SLANG_SPEC_BVEC4;
break;
default:
break;
}
break;
default:
break;
}
}
slang_typeinfo_destruct(&_ti);
}
break;
case SLANG_OPER_POSTINCREMENT:
case SLANG_OPER_POSTDECREMENT:
if (!_slang_typeof_operation_(op->children, space, ti, atoms, log))
return GL_FALSE;
ti->can_be_referenced = GL_FALSE;
ti->is_swizzled = GL_FALSE;
break;
default:
return GL_FALSE;
}
return GL_TRUE;
}
/**
* Lookup a function according to name and parameter count/types.
*/
slang_function *
_slang_locate_function(const slang_function_scope * funcs, slang_atom a_name,
slang_operation * args, GLuint num_args,
const slang_name_space * space, slang_atom_pool * atoms,
slang_info_log *log, GLboolean *error)
{
slang_typeinfo arg_ti[100];
GLuint i;
*error = GL_FALSE;
/* determine type of each argument */
assert(num_args < 100);
for (i = 0; i < num_args; i++) {
if (!slang_typeinfo_construct(&arg_ti[i]))
return NULL;
if (!_slang_typeof_operation_(&args[i], space, &arg_ti[i], atoms, log)) {
return NULL;
}
}
/* loop over function scopes */
while (funcs) {
/* look for function with matching name and argument/param types */
for (i = 0; i < funcs->num_functions; i++) {
slang_function *f = &funcs->functions[i];
const GLuint haveRetValue = _slang_function_has_return_value(f);
GLuint j;
if (a_name != f->header.a_name)
continue;
if (f->param_count - haveRetValue != num_args)
continue;
/* compare parameter / argument types */
for (j = 0; j < num_args; j++) {
if (!slang_type_specifier_compatible(&arg_ti[j].spec,
&f->parameters->variables[j]->type.specifier)) {
/* param/arg types don't match */
break;
}
/* "out" and "inout" formal parameter requires the actual
* argument to be an l-value.
*/
if (!arg_ti[j].can_be_referenced &&
(f->parameters->variables[j]->type.qualifier == SLANG_QUAL_OUT ||
f->parameters->variables[j]->type.qualifier == SLANG_QUAL_INOUT)) {
/* param is not an lvalue! */
*error = GL_TRUE;
return NULL;
}
}
if (j == num_args) {
/* name and args match! */
return f;
}
}
funcs = funcs->outer_scope;
}
return NULL;
}
/**
* Determine if a type is a matrix.
* \return GL_TRUE if is a matrix, GL_FALSE otherwise.
*/
GLboolean
_slang_type_is_matrix(slang_type_specifier_type ty)
{
switch (ty) {
case SLANG_SPEC_MAT2:
case SLANG_SPEC_MAT3:
case SLANG_SPEC_MAT4:
case SLANG_SPEC_MAT23:
case SLANG_SPEC_MAT32:
case SLANG_SPEC_MAT24:
case SLANG_SPEC_MAT42:
case SLANG_SPEC_MAT34:
case SLANG_SPEC_MAT43:
return GL_TRUE;
default:
return GL_FALSE;
}
}
/**
* Determine if a type is a vector.
* \return GL_TRUE if is a vector, GL_FALSE otherwise.
*/
GLboolean
_slang_type_is_vector(slang_type_specifier_type ty)
{
switch (ty) {
case SLANG_SPEC_VEC2:
case SLANG_SPEC_VEC3:
case SLANG_SPEC_VEC4:
case SLANG_SPEC_IVEC2:
case SLANG_SPEC_IVEC3:
case SLANG_SPEC_IVEC4:
case SLANG_SPEC_BVEC2:
case SLANG_SPEC_BVEC3:
case SLANG_SPEC_BVEC4:
return GL_TRUE;
default:
return GL_FALSE;
}
}
/**
* Determine if a type is a float, float vector or float matrix.
* \return GL_TRUE if so, GL_FALSE otherwise
*/
GLboolean
_slang_type_is_float_vec_mat(slang_type_specifier_type ty)
{
switch (ty) {
case SLANG_SPEC_FLOAT:
case SLANG_SPEC_VEC2:
case SLANG_SPEC_VEC3:
case SLANG_SPEC_VEC4:
case SLANG_SPEC_MAT2:
case SLANG_SPEC_MAT3:
case SLANG_SPEC_MAT4:
case SLANG_SPEC_MAT23:
case SLANG_SPEC_MAT32:
case SLANG_SPEC_MAT24:
case SLANG_SPEC_MAT42:
case SLANG_SPEC_MAT34:
case SLANG_SPEC_MAT43:
return GL_TRUE;
default:
return GL_FALSE;
}
}
/**
* Given a vector type, return the type of the vector's elements.
* For a matrix, return the type of the columns.
*/
slang_type_specifier_type
_slang_type_base(slang_type_specifier_type ty)
{
switch (ty) {
case SLANG_SPEC_FLOAT:
case SLANG_SPEC_VEC2:
case SLANG_SPEC_VEC3:
case SLANG_SPEC_VEC4:
return SLANG_SPEC_FLOAT;
case SLANG_SPEC_INT:
case SLANG_SPEC_IVEC2:
case SLANG_SPEC_IVEC3:
case SLANG_SPEC_IVEC4:
return SLANG_SPEC_INT;
case SLANG_SPEC_BOOL:
case SLANG_SPEC_BVEC2:
case SLANG_SPEC_BVEC3:
case SLANG_SPEC_BVEC4:
return SLANG_SPEC_BOOL;
case SLANG_SPEC_MAT2:
return SLANG_SPEC_VEC2;
case SLANG_SPEC_MAT3:
return SLANG_SPEC_VEC3;
case SLANG_SPEC_MAT4:
return SLANG_SPEC_VEC4;
case SLANG_SPEC_MAT23:
return SLANG_SPEC_VEC3;
case SLANG_SPEC_MAT32:
return SLANG_SPEC_VEC2;
case SLANG_SPEC_MAT24:
return SLANG_SPEC_VEC4;
case SLANG_SPEC_MAT42:
return SLANG_SPEC_VEC2;
case SLANG_SPEC_MAT34:
return SLANG_SPEC_VEC4;
case SLANG_SPEC_MAT43:
return SLANG_SPEC_VEC3;
default:
return SLANG_SPEC_VOID;
}
}
/**
* Return the dimensionality of a vector, or for a matrix, return number
* of columns.
*/
GLuint
_slang_type_dim(slang_type_specifier_type ty)
{
switch (ty) {
case SLANG_SPEC_FLOAT:
case SLANG_SPEC_INT:
case SLANG_SPEC_BOOL:
return 1;
case SLANG_SPEC_VEC2:
case SLANG_SPEC_IVEC2:
case SLANG_SPEC_BVEC2:
case SLANG_SPEC_MAT2:
return 2;
case SLANG_SPEC_VEC3:
case SLANG_SPEC_IVEC3:
case SLANG_SPEC_BVEC3:
case SLANG_SPEC_MAT3:
return 3;
case SLANG_SPEC_VEC4:
case SLANG_SPEC_IVEC4:
case SLANG_SPEC_BVEC4:
case SLANG_SPEC_MAT4:
return 4;
case SLANG_SPEC_MAT23:
return 2;
case SLANG_SPEC_MAT32:
return 3;
case SLANG_SPEC_MAT24:
return 2;
case SLANG_SPEC_MAT42:
return 4;
case SLANG_SPEC_MAT34:
return 3;
case SLANG_SPEC_MAT43:
return 4;
default:
return 0;
}
}
/**
* Return the GL_* type that corresponds to a SLANG_SPEC_* type.
*/
GLenum
_slang_gltype_from_specifier(const slang_type_specifier *type)
{
switch (type->type) {
case SLANG_SPEC_BOOL:
return GL_BOOL;
case SLANG_SPEC_BVEC2:
return GL_BOOL_VEC2;
case SLANG_SPEC_BVEC3:
return GL_BOOL_VEC3;
case SLANG_SPEC_BVEC4:
return GL_BOOL_VEC4;
case SLANG_SPEC_INT:
return GL_INT;
case SLANG_SPEC_IVEC2:
return GL_INT_VEC2;
case SLANG_SPEC_IVEC3:
return GL_INT_VEC3;
case SLANG_SPEC_IVEC4:
return GL_INT_VEC4;
case SLANG_SPEC_FLOAT:
return GL_FLOAT;
case SLANG_SPEC_VEC2:
return GL_FLOAT_VEC2;
case SLANG_SPEC_VEC3:
return GL_FLOAT_VEC3;
case SLANG_SPEC_VEC4:
return GL_FLOAT_VEC4;
case SLANG_SPEC_MAT2:
return GL_FLOAT_MAT2;
case SLANG_SPEC_MAT3:
return GL_FLOAT_MAT3;
case SLANG_SPEC_MAT4:
return GL_FLOAT_MAT4;
case SLANG_SPEC_MAT23:
return GL_FLOAT_MAT2x3;
case SLANG_SPEC_MAT32:
return GL_FLOAT_MAT3x2;
case SLANG_SPEC_MAT24:
return GL_FLOAT_MAT2x4;
case SLANG_SPEC_MAT42:
return GL_FLOAT_MAT4x2;
case SLANG_SPEC_MAT34:
return GL_FLOAT_MAT3x4;
case SLANG_SPEC_MAT43:
return GL_FLOAT_MAT4x3;
case SLANG_SPEC_SAMPLER1D:
return GL_SAMPLER_1D;
case SLANG_SPEC_SAMPLER2D:
return GL_SAMPLER_2D;
case SLANG_SPEC_SAMPLER3D:
return GL_SAMPLER_3D;
case SLANG_SPEC_SAMPLERCUBE:
return GL_SAMPLER_CUBE;
case SLANG_SPEC_SAMPLER1DSHADOW:
return GL_SAMPLER_1D_SHADOW;
case SLANG_SPEC_SAMPLER2DSHADOW:
return GL_SAMPLER_2D_SHADOW;
case SLANG_SPEC_SAMPLER2DRECT:
return GL_SAMPLER_2D_RECT_ARB;
case SLANG_SPEC_SAMPLER2DRECTSHADOW:
return GL_SAMPLER_2D_RECT_SHADOW_ARB;
case SLANG_SPEC_ARRAY:
return _slang_gltype_from_specifier(type->_array);
case SLANG_SPEC_STRUCT:
/* fall-through */
default:
return GL_NONE;
}
}