mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-05 09:38:07 +02:00
glsl: add ast/parser support for subroutine parsing storage (v3.2)
This is the guts of the GLSL parser and AST support for shader subroutines. The code creates a subroutine type in the parser, and uses that there to validate the identifiers. The parser also distinguishes between subroutine types/function prototypes /uniforms and subroutine defintions for functions. Then in the AST conversion it recreates the types, and stores the subroutine definition info or subroutine info into the ir_function along with a side lookup table in the parser state. It also converts subroutine calls into the enhanced ir_call. v2: move to handling method calls in function handling not in field selection. v3: merge Chris's previous parser patches in here, to make it clearer what's changed in one place. v3.1: add more documentation, drop unused include v3.2: drop is_subroutine_def Reviewed-by: Chris Forbes <chrisf@ijw.co.nz> Signed-off-by: Dave Airlie <airlied@redhat.com>
This commit is contained in:
parent
884df9ef83
commit
65ac360823
9 changed files with 326 additions and 116 deletions
|
|
@ -304,6 +304,16 @@ private:
|
|||
* Is this function call actually a constructor?
|
||||
*/
|
||||
bool cons;
|
||||
ir_rvalue *
|
||||
handle_method(exec_list *instructions,
|
||||
struct _mesa_glsl_parse_state *state);
|
||||
};
|
||||
|
||||
class ast_subroutine_list : public ast_node
|
||||
{
|
||||
public:
|
||||
virtual void print(void) const;
|
||||
exec_list declarations;
|
||||
};
|
||||
|
||||
class ast_array_specifier : public ast_node {
|
||||
|
|
@ -527,6 +537,12 @@ struct ast_type_qualifier {
|
|||
/* tess control output layout */
|
||||
unsigned vertices:1;
|
||||
/** \} */
|
||||
|
||||
/** \name Qualifiers for GL_ARB_shader_subroutine */
|
||||
/** \{ */
|
||||
unsigned subroutine:1; /**< Is this marked 'subroutine' */
|
||||
unsigned subroutine_def:1; /**< Is this marked 'subroutine' with a list of types */
|
||||
/** \} */
|
||||
}
|
||||
/** \brief Set of flags, accessed by name. */
|
||||
q;
|
||||
|
|
@ -669,6 +685,7 @@ struct ast_type_qualifier {
|
|||
ast_type_qualifier q,
|
||||
ast_node* &node);
|
||||
|
||||
ast_subroutine_list *subroutine_list;
|
||||
};
|
||||
|
||||
class ast_declarator_list;
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include "glsl_types.h"
|
||||
#include "ir.h"
|
||||
#include "main/core.h" /* for MIN2 */
|
||||
#include "main/shaderobj.h"
|
||||
|
||||
static ir_rvalue *
|
||||
convert_component(ir_rvalue *src, const glsl_type *desired_type);
|
||||
|
|
@ -355,6 +356,8 @@ fix_parameter(void *mem_ctx, ir_rvalue *actual, const glsl_type *formal_type,
|
|||
static ir_rvalue *
|
||||
generate_call(exec_list *instructions, ir_function_signature *sig,
|
||||
exec_list *actual_parameters,
|
||||
ir_variable *sub_var,
|
||||
ir_rvalue *array_idx,
|
||||
struct _mesa_glsl_parse_state *state)
|
||||
{
|
||||
void *ctx = state;
|
||||
|
|
@ -421,7 +424,8 @@ generate_call(exec_list *instructions, ir_function_signature *sig,
|
|||
|
||||
deref = new(ctx) ir_dereference_variable(var);
|
||||
}
|
||||
ir_call *call = new(ctx) ir_call(sig, deref, actual_parameters);
|
||||
|
||||
ir_call *call = new(ctx) ir_call(sig, deref, actual_parameters, sub_var, array_idx);
|
||||
instructions->push_tail(call);
|
||||
|
||||
/* Also emit any necessary out-parameter conversions. */
|
||||
|
|
@ -489,6 +493,40 @@ done:
|
|||
return sig;
|
||||
}
|
||||
|
||||
static ir_function_signature *
|
||||
match_subroutine_by_name(const char *name,
|
||||
exec_list *actual_parameters,
|
||||
struct _mesa_glsl_parse_state *state,
|
||||
ir_variable **var_r)
|
||||
{
|
||||
void *ctx = state;
|
||||
ir_function_signature *sig = NULL;
|
||||
ir_function *f, *found = NULL;
|
||||
const char *new_name;
|
||||
ir_variable *var;
|
||||
bool is_exact = false;
|
||||
|
||||
new_name = ralloc_asprintf(ctx, "%s_%s", _mesa_shader_stage_to_subroutine_prefix(state->stage), name);
|
||||
var = state->symbols->get_variable(new_name);
|
||||
if (!var)
|
||||
return NULL;
|
||||
|
||||
for (int i = 0; i < state->num_subroutine_types; i++) {
|
||||
f = state->subroutine_types[i];
|
||||
if (strcmp(f->name, var->type->without_array()->name))
|
||||
continue;
|
||||
found = f;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
return NULL;
|
||||
*var_r = var;
|
||||
sig = found->matching_signature(state, actual_parameters,
|
||||
false, &is_exact);
|
||||
return sig;
|
||||
}
|
||||
|
||||
static void
|
||||
print_function_prototypes(_mesa_glsl_parse_state *state, YYLTYPE *loc,
|
||||
ir_function *f)
|
||||
|
|
@ -1531,6 +1569,65 @@ process_record_constructor(exec_list *instructions,
|
|||
&actual_parameters, state);
|
||||
}
|
||||
|
||||
ir_rvalue *
|
||||
ast_function_expression::handle_method(exec_list *instructions,
|
||||
struct _mesa_glsl_parse_state *state)
|
||||
{
|
||||
const ast_expression *field = subexpressions[0];
|
||||
ir_rvalue *op;
|
||||
ir_rvalue *result;
|
||||
void *ctx = state;
|
||||
/* Handle "method calls" in GLSL 1.20 - namely, array.length() */
|
||||
YYLTYPE loc = get_location();
|
||||
state->check_version(120, 300, &loc, "methods not supported");
|
||||
|
||||
const char *method;
|
||||
method = field->primary_expression.identifier;
|
||||
|
||||
op = field->subexpressions[0]->hir(instructions, state);
|
||||
if (strcmp(method, "length") == 0) {
|
||||
if (!this->expressions.is_empty()) {
|
||||
_mesa_glsl_error(&loc, state, "length method takes no arguments");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (op->type->is_array()) {
|
||||
if (op->type->is_unsized_array()) {
|
||||
_mesa_glsl_error(&loc, state, "length called on unsized array");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
result = new(ctx) ir_constant(op->type->array_size());
|
||||
} else if (op->type->is_vector()) {
|
||||
if (state->ARB_shading_language_420pack_enable) {
|
||||
/* .length() returns int. */
|
||||
result = new(ctx) ir_constant((int) op->type->vector_elements);
|
||||
} else {
|
||||
_mesa_glsl_error(&loc, state, "length method on matrix only available"
|
||||
"with ARB_shading_language_420pack");
|
||||
goto fail;
|
||||
}
|
||||
} else if (op->type->is_matrix()) {
|
||||
if (state->ARB_shading_language_420pack_enable) {
|
||||
/* .length() returns int. */
|
||||
result = new(ctx) ir_constant((int) op->type->matrix_columns);
|
||||
} else {
|
||||
_mesa_glsl_error(&loc, state, "length method on matrix only available"
|
||||
"with ARB_shading_language_420pack");
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
_mesa_glsl_error(&loc, state, "length called on scalar.");
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
_mesa_glsl_error(&loc, state, "unknown method: `%s'", method);
|
||||
goto fail;
|
||||
}
|
||||
return result;
|
||||
fail:
|
||||
return ir_rvalue::error_value(ctx);
|
||||
}
|
||||
|
||||
ir_rvalue *
|
||||
ast_function_expression::hir(exec_list *instructions,
|
||||
|
|
@ -1543,8 +1640,6 @@ ast_function_expression::hir(exec_list *instructions,
|
|||
* 2. methods - Only the .length() method of array types.
|
||||
* 3. functions - Calls to regular old functions.
|
||||
*
|
||||
* Method calls are actually detected when the ast_field_selection
|
||||
* expression is handled.
|
||||
*/
|
||||
if (is_constructor()) {
|
||||
const ast_type_specifier *type = (ast_type_specifier *) subexpressions[0];
|
||||
|
|
@ -1765,11 +1860,22 @@ ast_function_expression::hir(exec_list *instructions,
|
|||
&actual_parameters,
|
||||
ctx);
|
||||
}
|
||||
} else if (subexpressions[0]->oper == ast_field_selection) {
|
||||
return handle_method(instructions, state);
|
||||
} else {
|
||||
const ast_expression *id = subexpressions[0];
|
||||
const char *func_name = id->primary_expression.identifier;
|
||||
const char *func_name;
|
||||
YYLTYPE loc = get_location();
|
||||
exec_list actual_parameters;
|
||||
ir_variable *sub_var = NULL;
|
||||
ir_rvalue *array_idx = NULL;
|
||||
|
||||
if (id->oper == ast_array_index) {
|
||||
func_name = id->subexpressions[0]->primary_expression.identifier;
|
||||
array_idx = id->subexpressions[1]->hir(instructions, state);
|
||||
} else {
|
||||
func_name = id->primary_expression.identifier;
|
||||
}
|
||||
|
||||
process_parameters(instructions, &actual_parameters, &this->expressions,
|
||||
state);
|
||||
|
|
@ -1778,6 +1884,10 @@ ast_function_expression::hir(exec_list *instructions,
|
|||
match_function_by_name(func_name, &actual_parameters, state);
|
||||
|
||||
ir_rvalue *value = NULL;
|
||||
if (sig == NULL) {
|
||||
sig = match_subroutine_by_name(func_name, &actual_parameters, state, &sub_var);
|
||||
}
|
||||
|
||||
if (sig == NULL) {
|
||||
no_matching_function_error(func_name, &loc, &actual_parameters, state);
|
||||
value = ir_rvalue::error_value(ctx);
|
||||
|
|
@ -1785,7 +1895,7 @@ ast_function_expression::hir(exec_list *instructions,
|
|||
/* an error has already been emitted */
|
||||
value = ir_rvalue::error_value(ctx);
|
||||
} else {
|
||||
value = generate_call(instructions, sig, &actual_parameters, state);
|
||||
value = generate_call(instructions, sig, &actual_parameters, sub_var, array_idx, state);
|
||||
if (!value) {
|
||||
ir_variable *const tmp = new(ctx) ir_variable(glsl_type::void_type,
|
||||
"void_var",
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@
|
|||
#include "ast.h"
|
||||
#include "glsl_types.h"
|
||||
#include "program/hash_table.h"
|
||||
#include "main/shaderobj.h"
|
||||
#include "ir.h"
|
||||
#include "ir_builder.h"
|
||||
|
||||
|
|
@ -2522,6 +2523,12 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual,
|
|||
}
|
||||
}
|
||||
|
||||
if (qual->flags.q.subroutine && !qual->flags.q.uniform) {
|
||||
_mesa_glsl_error(loc, state,
|
||||
"`subroutine' may only be applied to uniforms, "
|
||||
"subroutine type declarations, or function definitions");
|
||||
}
|
||||
|
||||
if (qual->flags.q.constant || qual->flags.q.attribute
|
||||
|| qual->flags.q.uniform
|
||||
|| (qual->flags.q.varying && (state->stage == MESA_SHADER_FRAGMENT)))
|
||||
|
|
@ -3597,7 +3604,7 @@ ast_declarator_list::hir(exec_list *instructions,
|
|||
foreach_list_typed (ast_declaration, decl, link, &this->declarations) {
|
||||
const struct glsl_type *var_type;
|
||||
ir_variable *var;
|
||||
|
||||
const char *identifier = decl->identifier;
|
||||
/* FINISHME: Emit a warning if a variable declaration shadows a
|
||||
* FINISHME: declaration at a higher scope.
|
||||
*/
|
||||
|
|
@ -3615,10 +3622,24 @@ ast_declarator_list::hir(exec_list *instructions,
|
|||
continue;
|
||||
}
|
||||
|
||||
if (this->type->qualifier.flags.q.subroutine) {
|
||||
const glsl_type *t;
|
||||
const char *name;
|
||||
|
||||
t = state->symbols->get_type(this->type->specifier->type_name);
|
||||
if (!t)
|
||||
_mesa_glsl_error(& loc, state,
|
||||
"invalid type in declaration of `%s'",
|
||||
decl->identifier);
|
||||
name = ralloc_asprintf(ctx, "%s_%s", _mesa_shader_stage_to_subroutine_prefix(state->stage), decl->identifier);
|
||||
|
||||
identifier = name;
|
||||
|
||||
}
|
||||
var_type = process_array_type(&loc, decl_type, decl->array_specifier,
|
||||
state);
|
||||
|
||||
var = new(ctx) ir_variable(var_type, decl->identifier, ir_var_auto);
|
||||
var = new(ctx) ir_variable(var_type, identifier, ir_var_auto);
|
||||
|
||||
/* The 'varying in' and 'varying out' qualifiers can only be used with
|
||||
* ARB_geometry_shader4 and EXT_geometry_shader4, which we don't support
|
||||
|
|
@ -3690,6 +3711,8 @@ ast_declarator_list::hir(exec_list *instructions,
|
|||
*/
|
||||
if (this->type->qualifier.flags.q.attribute) {
|
||||
mode = "attribute";
|
||||
} else if (this->type->qualifier.flags.q.subroutine) {
|
||||
mode = "subroutine uniform";
|
||||
} else if (this->type->qualifier.flags.q.uniform) {
|
||||
mode = "uniform";
|
||||
} else if (this->type->qualifier.flags.q.varying) {
|
||||
|
|
@ -3930,6 +3953,9 @@ ast_declarator_list::hir(exec_list *instructions,
|
|||
if (state->stage == MESA_SHADER_TESS_CTRL) {
|
||||
handle_tess_ctrl_shader_output_decl(state, loc, var);
|
||||
}
|
||||
} else if (var->type->contains_subroutine()) {
|
||||
/* declare subroutine uniforms as hidden */
|
||||
var->data.how_declared = ir_var_hidden;
|
||||
}
|
||||
|
||||
/* Integer fragment inputs must be qualified with 'flat'. In GLSL ES,
|
||||
|
|
@ -4394,6 +4420,7 @@ ast_function::hir(exec_list *instructions,
|
|||
ir_function *f = NULL;
|
||||
ir_function_signature *sig = NULL;
|
||||
exec_list hir_parameters;
|
||||
YYLTYPE loc = this->get_location();
|
||||
|
||||
const char *const name = identifier;
|
||||
|
||||
|
|
@ -4445,6 +4472,17 @@ ast_function::hir(exec_list *instructions,
|
|||
return_type = glsl_type::error_type;
|
||||
}
|
||||
|
||||
/* ARB_shader_subroutine states:
|
||||
* "Subroutine declarations cannot be prototyped. It is an error to prepend
|
||||
* subroutine(...) to a function declaration."
|
||||
*/
|
||||
if (this->return_type->qualifier.flags.q.subroutine_def && !is_definition) {
|
||||
YYLTYPE loc = this->get_location();
|
||||
_mesa_glsl_error(&loc, state,
|
||||
"function declaration `%s' cannot have subroutine prepended",
|
||||
name);
|
||||
}
|
||||
|
||||
/* From page 56 (page 62 of the PDF) of the GLSL 1.30 spec:
|
||||
* "No qualifier is allowed on the return type of a function."
|
||||
*/
|
||||
|
|
@ -4482,15 +4520,15 @@ ast_function::hir(exec_list *instructions,
|
|||
f = state->symbols->get_function(name);
|
||||
if (f == NULL) {
|
||||
f = new(ctx) ir_function(name);
|
||||
if (!state->symbols->add_function(f)) {
|
||||
/* This function name shadows a non-function use of the same name. */
|
||||
YYLTYPE loc = this->get_location();
|
||||
|
||||
_mesa_glsl_error(&loc, state, "function name `%s' conflicts with "
|
||||
"non-function", name);
|
||||
return NULL;
|
||||
if (!this->return_type->qualifier.flags.q.subroutine) {
|
||||
if (!state->symbols->add_function(f)) {
|
||||
/* This function name shadows a non-function use of the same name. */
|
||||
YYLTYPE loc = this->get_location();
|
||||
_mesa_glsl_error(&loc, state, "function name `%s' conflicts with "
|
||||
"non-function", name);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
emit_function(state, f);
|
||||
}
|
||||
|
||||
|
|
@ -4577,6 +4615,44 @@ ast_function::hir(exec_list *instructions,
|
|||
sig->replace_parameters(&hir_parameters);
|
||||
signature = sig;
|
||||
|
||||
if (this->return_type->qualifier.flags.q.subroutine_def) {
|
||||
int idx;
|
||||
|
||||
f->num_subroutine_types = this->return_type->qualifier.subroutine_list->declarations.length();
|
||||
f->subroutine_types = ralloc_array(state, const struct glsl_type *,
|
||||
f->num_subroutine_types);
|
||||
idx = 0;
|
||||
foreach_list_typed(ast_declaration, decl, link, &this->return_type->qualifier.subroutine_list->declarations) {
|
||||
const struct glsl_type *type;
|
||||
/* the subroutine type must be already declared */
|
||||
type = state->symbols->get_type(decl->identifier);
|
||||
if (!type) {
|
||||
_mesa_glsl_error(& loc, state, "unknown type '%s' in subroutine function definition", decl->identifier);
|
||||
}
|
||||
f->subroutine_types[idx++] = type;
|
||||
}
|
||||
state->subroutines = (ir_function **)reralloc(state, state->subroutines,
|
||||
ir_function *,
|
||||
state->num_subroutines + 1);
|
||||
state->subroutines[state->num_subroutines] = f;
|
||||
state->num_subroutines++;
|
||||
|
||||
}
|
||||
|
||||
if (this->return_type->qualifier.flags.q.subroutine) {
|
||||
if (!state->symbols->add_type(this->identifier, glsl_type::get_subroutine_instance(this->identifier))) {
|
||||
_mesa_glsl_error(& loc, state, "type '%s' previously defined", this->identifier);
|
||||
return NULL;
|
||||
}
|
||||
state->subroutine_types = (ir_function **)reralloc(state, state->subroutine_types,
|
||||
ir_function *,
|
||||
state->num_subroutine_types + 1);
|
||||
state->subroutine_types[state->num_subroutine_types] = f;
|
||||
state->num_subroutine_types++;
|
||||
|
||||
f->is_subroutine = true;
|
||||
}
|
||||
|
||||
/* Function declarations (prototypes) do not have r-values.
|
||||
*/
|
||||
return NULL;
|
||||
|
|
|
|||
|
|
@ -40,7 +40,12 @@ ast_type_specifier::print(void) const
|
|||
bool
|
||||
ast_fully_specified_type::has_qualifiers() const
|
||||
{
|
||||
return this->qualifier.flags.i != 0;
|
||||
/* 'subroutine' isnt a real qualifier. */
|
||||
ast_type_qualifier subroutine_only;
|
||||
subroutine_only.flags.i = 0;
|
||||
subroutine_only.flags.q.subroutine = 1;
|
||||
subroutine_only.flags.q.subroutine_def = 1;
|
||||
return (this->qualifier.flags.i & ~subroutine_only.flags.i) != 0;
|
||||
}
|
||||
|
||||
bool ast_type_qualifier::has_interpolation() const
|
||||
|
|
|
|||
|
|
@ -595,6 +595,10 @@ subroutine KEYWORD_WITH_ALT(400, 300, 400, 0, yyextra->ARB_shader_subroutine_ena
|
|||
return classify_identifier(state, yytext);
|
||||
}
|
||||
|
||||
\. { struct _mesa_glsl_parse_state *state = yyextra;
|
||||
state->is_field = true;
|
||||
return DOT_TOK; }
|
||||
|
||||
. { return yytext[0]; }
|
||||
|
||||
%%
|
||||
|
|
@ -602,6 +606,10 @@ subroutine KEYWORD_WITH_ALT(400, 300, 400, 0, yyextra->ARB_shader_subroutine_ena
|
|||
int
|
||||
classify_identifier(struct _mesa_glsl_parse_state *state, const char *name)
|
||||
{
|
||||
if (state->is_field) {
|
||||
state->is_field = false;
|
||||
return FIELD_SELECTION;
|
||||
}
|
||||
if (state->symbols->get_variable(name) || state->symbols->get_function(name))
|
||||
return IDENTIFIER;
|
||||
else if (state->symbols->get_type(name))
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ static bool match_layout_qualifier(const char *s1, const char *s2,
|
|||
ast_case_statement *case_statement;
|
||||
ast_case_statement_list *case_statement_list;
|
||||
ast_interface_block *interface_block;
|
||||
|
||||
ast_subroutine_list *subroutine_list;
|
||||
struct {
|
||||
ast_node *cond;
|
||||
ast_expression *rest;
|
||||
|
|
@ -186,7 +186,7 @@ static bool match_layout_qualifier(const char *s1, const char *s2,
|
|||
%token PRAGMA_OPTIMIZE_ON PRAGMA_OPTIMIZE_OFF
|
||||
%token PRAGMA_INVARIANT_ALL
|
||||
%token LAYOUT_TOK
|
||||
|
||||
%token DOT_TOK
|
||||
/* Reserved words that are not actually used in the grammar.
|
||||
*/
|
||||
%token ASM CLASS UNION ENUM TYPEDEF TEMPLATE THIS PACKED_TOK GOTO
|
||||
|
|
@ -215,6 +215,8 @@ static bool match_layout_qualifier(const char *s1, const char *s2,
|
|||
%type <type_qualifier> layout_qualifier_id_list layout_qualifier_id
|
||||
%type <type_qualifier> interface_block_layout_qualifier
|
||||
%type <type_qualifier> memory_qualifier
|
||||
%type <type_qualifier> subroutine_qualifier
|
||||
%type <subroutine_list> subroutine_type_list
|
||||
%type <type_qualifier> interface_qualifier
|
||||
%type <type_specifier> type_specifier
|
||||
%type <type_specifier> type_specifier_nonarray
|
||||
|
|
@ -260,10 +262,6 @@ static bool match_layout_qualifier(const char *s1, const char *s2,
|
|||
%type <expression> function_call_generic
|
||||
%type <expression> function_call_or_method
|
||||
%type <expression> function_call
|
||||
%type <expression> method_call_generic
|
||||
%type <expression> method_call_header_with_parameters
|
||||
%type <expression> method_call_header_no_parameters
|
||||
%type <expression> method_call_header
|
||||
%type <n> assignment_operator
|
||||
%type <n> unary_operator
|
||||
%type <expression> function_identifier
|
||||
|
|
@ -476,7 +474,7 @@ postfix_expression:
|
|||
{
|
||||
$$ = $1;
|
||||
}
|
||||
| postfix_expression '.' any_identifier
|
||||
| postfix_expression DOT_TOK FIELD_SELECTION
|
||||
{
|
||||
void *ctx = state;
|
||||
$$ = new(ctx) ast_expression(ast_field_selection, $1, NULL, NULL);
|
||||
|
|
@ -507,12 +505,6 @@ function_call:
|
|||
|
||||
function_call_or_method:
|
||||
function_call_generic
|
||||
| postfix_expression '.' method_call_generic
|
||||
{
|
||||
void *ctx = state;
|
||||
$$ = new(ctx) ast_expression(ast_field_selection, $1, $3, NULL);
|
||||
$$->set_location_range(@1, @3);
|
||||
}
|
||||
;
|
||||
|
||||
function_call_generic:
|
||||
|
|
@ -554,62 +546,17 @@ function_identifier:
|
|||
$$ = new(ctx) ast_function_expression($1);
|
||||
$$->set_location(@1);
|
||||
}
|
||||
| variable_identifier
|
||||
| postfix_expression
|
||||
{
|
||||
void *ctx = state;
|
||||
ast_expression *callee = new(ctx) ast_expression($1);
|
||||
callee->set_location(@1);
|
||||
$$ = new(ctx) ast_function_expression(callee);
|
||||
$$ = new(ctx) ast_function_expression($1);
|
||||
$$->set_location(@1);
|
||||
}
|
||||
| FIELD_SELECTION
|
||||
{
|
||||
void *ctx = state;
|
||||
ast_expression *callee = new(ctx) ast_expression($1);
|
||||
callee->set_location(@1);
|
||||
$$ = new(ctx) ast_function_expression(callee);
|
||||
$$->set_location(@1);
|
||||
}
|
||||
;
|
||||
|
||||
method_call_generic:
|
||||
method_call_header_with_parameters ')'
|
||||
| method_call_header_no_parameters ')'
|
||||
;
|
||||
|
||||
method_call_header_no_parameters:
|
||||
method_call_header VOID_TOK
|
||||
| method_call_header
|
||||
;
|
||||
|
||||
method_call_header_with_parameters:
|
||||
method_call_header assignment_expression
|
||||
{
|
||||
$$ = $1;
|
||||
$$->set_location(@1);
|
||||
$$->expressions.push_tail(& $2->link);
|
||||
}
|
||||
| method_call_header_with_parameters ',' assignment_expression
|
||||
{
|
||||
$$ = $1;
|
||||
$$->set_location(@1);
|
||||
$$->expressions.push_tail(& $3->link);
|
||||
}
|
||||
;
|
||||
|
||||
// Grammar Note: Constructors look like methods, but lexical
|
||||
// analysis recognized most of them as keywords. They are now
|
||||
// recognized through "type_specifier".
|
||||
method_call_header:
|
||||
variable_identifier '('
|
||||
{
|
||||
void *ctx = state;
|
||||
ast_expression *callee = new(ctx) ast_expression($1);
|
||||
callee->set_location(@1);
|
||||
$$ = new(ctx) ast_function_expression(callee);
|
||||
$$->set_location(@1);
|
||||
}
|
||||
;
|
||||
|
||||
// Grammar Note: No traditional style type casts.
|
||||
unary_expression:
|
||||
|
|
@ -910,7 +857,11 @@ function_header:
|
|||
$$->return_type = $1;
|
||||
$$->identifier = $2;
|
||||
|
||||
state->symbols->add_function(new(state) ir_function($2));
|
||||
if ($1->qualifier.flags.q.subroutine) {
|
||||
/* add type for IDENTIFIER search */
|
||||
state->symbols->add_type($2, glsl_type::get_subroutine_instance($2));
|
||||
} else
|
||||
state->symbols->add_function(new(state) ir_function($2));
|
||||
state->symbols->push_scope();
|
||||
}
|
||||
;
|
||||
|
|
@ -1676,6 +1627,41 @@ interface_block_layout_qualifier:
|
|||
}
|
||||
;
|
||||
|
||||
subroutine_qualifier:
|
||||
SUBROUTINE
|
||||
{
|
||||
memset(& $$, 0, sizeof($$));
|
||||
$$.flags.q.subroutine = 1;
|
||||
}
|
||||
| SUBROUTINE '(' subroutine_type_list ')'
|
||||
{
|
||||
memset(& $$, 0, sizeof($$));
|
||||
$$.flags.q.subroutine_def = 1;
|
||||
$$.subroutine_list = $3;
|
||||
}
|
||||
;
|
||||
|
||||
subroutine_type_list:
|
||||
any_identifier
|
||||
{
|
||||
void *ctx = state;
|
||||
ast_declaration *decl = new(ctx) ast_declaration($1, NULL, NULL);
|
||||
decl->set_location(@1);
|
||||
|
||||
$$ = new(ctx) ast_subroutine_list();
|
||||
$$->declarations.push_tail(&decl->link);
|
||||
}
|
||||
| subroutine_type_list ',' any_identifier
|
||||
{
|
||||
void *ctx = state;
|
||||
ast_declaration *decl = new(ctx) ast_declaration($3, NULL, NULL);
|
||||
decl->set_location(@3);
|
||||
|
||||
$$ = $1;
|
||||
$$->declarations.push_tail(&decl->link);
|
||||
}
|
||||
;
|
||||
|
||||
interpolation_qualifier:
|
||||
SMOOTH
|
||||
{
|
||||
|
|
@ -1711,6 +1697,7 @@ type_qualifier:
|
|||
| interpolation_qualifier
|
||||
| layout_qualifier
|
||||
| memory_qualifier
|
||||
| subroutine_qualifier
|
||||
| precision_qualifier
|
||||
{
|
||||
memset(&$$, 0, sizeof($$));
|
||||
|
|
@ -1801,6 +1788,11 @@ type_qualifier:
|
|||
$$ = $1;
|
||||
$$.merge_qualifier(&@1, state, $2);
|
||||
}
|
||||
| subroutine_qualifier type_qualifier
|
||||
{
|
||||
$$ = $1;
|
||||
$$.merge_qualifier(&@1, state, $2);
|
||||
}
|
||||
| auxiliary_storage_qualifier type_qualifier
|
||||
{
|
||||
if ($2.has_auxiliary_storage()) {
|
||||
|
|
|
|||
|
|
@ -173,6 +173,10 @@ _mesa_glsl_parse_state::_mesa_glsl_parse_state(struct gl_context *_ctx,
|
|||
this->all_invariant = false;
|
||||
this->user_structures = NULL;
|
||||
this->num_user_structures = 0;
|
||||
this->num_subroutines = 0;
|
||||
this->subroutines = NULL;
|
||||
this->num_subroutine_types = 0;
|
||||
this->subroutine_types = NULL;
|
||||
|
||||
/* supported_versions should be large enough to support the known desktop
|
||||
* GLSL versions plus 3 GLES versions (ES 1.00, ES 3.00, and ES 3.10))
|
||||
|
|
@ -855,6 +859,15 @@ _mesa_ast_set_aggregate_type(const glsl_type *type,
|
|||
void
|
||||
_mesa_ast_type_qualifier_print(const struct ast_type_qualifier *q)
|
||||
{
|
||||
if (q->flags.q.subroutine)
|
||||
printf("subroutine ");
|
||||
|
||||
if (q->flags.q.subroutine_def) {
|
||||
printf("subroutine (");
|
||||
q->subroutine_list->print();
|
||||
printf(")");
|
||||
}
|
||||
|
||||
if (q->flags.q.constant)
|
||||
printf("const ");
|
||||
|
||||
|
|
@ -1447,6 +1460,15 @@ ast_struct_specifier::ast_struct_specifier(const char *identifier,
|
|||
is_declaration = true;
|
||||
}
|
||||
|
||||
void ast_subroutine_list::print(void) const
|
||||
{
|
||||
foreach_list_typed (ast_node, ast, link, & this->declarations) {
|
||||
if (&ast->link != this->declarations.get_head())
|
||||
printf(", ");
|
||||
ast->print();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_shader_inout_layout(struct gl_shader *shader,
|
||||
struct _mesa_glsl_parse_state *state)
|
||||
|
|
|
|||
|
|
@ -589,6 +589,25 @@ struct _mesa_glsl_parse_state {
|
|||
unsigned atomic_counter_offsets[MAX_COMBINED_ATOMIC_BUFFERS];
|
||||
|
||||
bool allow_extension_directive_midshader;
|
||||
|
||||
/**
|
||||
* Known subroutine type declarations.
|
||||
*/
|
||||
int num_subroutine_types;
|
||||
ir_function **subroutine_types;
|
||||
|
||||
/**
|
||||
* Functions that are associated with
|
||||
* subroutine types.
|
||||
*/
|
||||
int num_subroutines;
|
||||
ir_function **subroutines;
|
||||
|
||||
/**
|
||||
* field selection temporary parser storage -
|
||||
* did the parser just parse a dot.
|
||||
*/
|
||||
bool is_field;
|
||||
};
|
||||
|
||||
# define YYLLOC_DEFAULT(Current, Rhs, N) \
|
||||
|
|
|
|||
|
|
@ -56,45 +56,6 @@ _mesa_ast_field_selection_to_hir(const ast_expression *expr,
|
|||
"structure",
|
||||
expr->primary_expression.identifier);
|
||||
}
|
||||
} else if (expr->subexpressions[1] != NULL) {
|
||||
/* Handle "method calls" in GLSL 1.20 - namely, array.length() */
|
||||
state->check_version(120, 300, &loc, "methods not supported");
|
||||
|
||||
ast_expression *call = expr->subexpressions[1];
|
||||
assert(call->oper == ast_function_call);
|
||||
|
||||
const char *method;
|
||||
method = call->subexpressions[0]->primary_expression.identifier;
|
||||
|
||||
if (strcmp(method, "length") == 0) {
|
||||
if (!call->expressions.is_empty())
|
||||
_mesa_glsl_error(&loc, state, "length method takes no arguments");
|
||||
|
||||
if (op->type->is_array()) {
|
||||
if (op->type->is_unsized_array())
|
||||
_mesa_glsl_error(&loc, state, "length called on unsized array");
|
||||
|
||||
result = new(ctx) ir_constant(op->type->array_size());
|
||||
} else if (op->type->is_vector()) {
|
||||
if (state->ARB_shading_language_420pack_enable) {
|
||||
/* .length() returns int. */
|
||||
result = new(ctx) ir_constant((int) op->type->vector_elements);
|
||||
} else {
|
||||
_mesa_glsl_error(&loc, state, "length method on matrix only available"
|
||||
"with ARB_shading_language_420pack");
|
||||
}
|
||||
} else if (op->type->is_matrix()) {
|
||||
if (state->ARB_shading_language_420pack_enable) {
|
||||
/* .length() returns int. */
|
||||
result = new(ctx) ir_constant((int) op->type->matrix_columns);
|
||||
} else {
|
||||
_mesa_glsl_error(&loc, state, "length method on matrix only available"
|
||||
"with ARB_shading_language_420pack");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_mesa_glsl_error(&loc, state, "unknown method: `%s'", method);
|
||||
}
|
||||
} else if (op->type->is_vector() ||
|
||||
(state->ARB_shading_language_420pack_enable &&
|
||||
op->type->is_scalar())) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue