X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fglsl%2Fir_reader.cpp;h=fd318c046e200436ea32d1d799004a8bca048900;hb=0e145a951e64e0b955e8315e22edf9e2ab4581ec;hp=40901dc6c92ea0cd16350dbd789aaf63f41d7644;hpb=bbafd2b849629d3155fe0eef655bbc166a901925;p=mesa.git diff --git a/src/glsl/ir_reader.cpp b/src/glsl/ir_reader.cpp index 40901dc6c92..fd318c046e2 100644 --- a/src/glsl/ir_reader.cpp +++ b/src/glsl/ir_reader.cpp @@ -21,10 +21,6 @@ * DEALINGS IN THE SOFTWARE. */ -extern "C" { -#include -} - #include "ir_reader.h" #include "glsl_parser_extras.h" #include "glsl_types.h" @@ -32,6 +28,8 @@ extern "C" { const static bool debug = false; +namespace { + class ir_reader { public: ir_reader(_mesa_glsl_parse_state *); @@ -55,18 +53,23 @@ private: ir_variable *read_declaration(s_expression *); ir_if *read_if(s_expression *, ir_loop *); ir_loop *read_loop(s_expression *); + ir_call *read_call(s_expression *); ir_return *read_return(s_expression *); ir_rvalue *read_rvalue(s_expression *); ir_assignment *read_assignment(s_expression *); ir_expression *read_expression(s_expression *); - ir_call *read_call(s_expression *); ir_swizzle *read_swizzle(s_expression *); ir_constant *read_constant(s_expression *); ir_texture *read_texture(s_expression *); + ir_emit_vertex *read_emit_vertex(s_expression *); + ir_end_primitive *read_end_primitive(s_expression *); ir_dereference *read_dereference(s_expression *); + ir_dereference_variable *read_var_ref(s_expression *); }; +} /* anonymous namespace */ + ir_reader::ir_reader(_mesa_glsl_parse_state *state) : state(state) { this->mem_ctx = state; @@ -83,7 +86,8 @@ _mesa_glsl_read_ir(_mesa_glsl_parse_state *state, exec_list *instructions, void ir_reader::read(exec_list *instructions, const char *src, bool scan_for_protos) { - s_expression *expr = s_expression::read_expression(mem_ctx, src); + void *sx_mem_ctx = ralloc_context(NULL); + s_expression *expr = s_expression::read_expression(sx_mem_ctx, src); if (expr == NULL) { ir_read_error(NULL, "couldn't parse S-Expression."); return; @@ -96,7 +100,7 @@ ir_reader::read(exec_list *instructions, const char *src, bool scan_for_protos) } read_instructions(instructions, expr, NULL); - talloc_free(expr); + ralloc_free(sx_mem_ctx); if (debug) validate_ir_tree(instructions); @@ -110,21 +114,19 @@ ir_reader::ir_read_error(s_expression *expr, const char *fmt, ...) state->error = true; if (state->current_function != NULL) - state->info_log = talloc_asprintf_append(state->info_log, - "In function %s:\n", - state->current_function->function_name()); - state->info_log = talloc_strdup_append(state->info_log, "error: "); + ralloc_asprintf_append(&state->info_log, "In function %s:\n", + state->current_function->function_name()); + ralloc_strcat(&state->info_log, "error: "); va_start(ap, fmt); - state->info_log = talloc_vasprintf_append(state->info_log, fmt, ap); + ralloc_vasprintf_append(&state->info_log, fmt, ap); va_end(ap); - state->info_log = talloc_strdup_append(state->info_log, "\n"); + ralloc_strcat(&state->info_log, "\n"); if (expr != NULL) { - state->info_log = talloc_strdup_append(state->info_log, - "...in this context:\n "); + ralloc_strcat(&state->info_log, "...in this context:\n "); expr->print(); - state->info_log = talloc_strdup_append(state->info_log, "\n\n"); + ralloc_strcat(&state->info_log, "\n\n"); } } @@ -168,9 +170,8 @@ ir_reader::scan_for_prototypes(exec_list *instructions, s_expression *expr) return; } - foreach_iter(exec_list_iterator, it, list->subexpressions) { - s_list *sub = SX_AS_LIST(it.get()); - if (sub == NULL) + foreach_in_list(s_list, sub, &list->subexpressions) { + if (!sub->is_list()) continue; // not a (function ...); ignore it. s_symbol *tag = SX_AS_SYMBOL(sub->subexpressions.get_head()); @@ -203,16 +204,23 @@ ir_reader::read_function(s_expression *expr, bool skip_body) assert(added); } - exec_list_iterator it = ((s_list *) expr)->subexpressions.iterator(); - it.next(); // skip "function" tag - it.next(); // skip function name - for (/* nothing */; it.has_next(); it.next()) { - s_expression *s_sig = (s_expression *) it.get(); + /* Skip over "function" tag and function name (which are guaranteed to be + * present by the above PARTIAL_MATCH call). + */ + exec_node *node = ((s_list *) expr)->subexpressions.head->next->next; + for (/* nothing */; !node->is_tail_sentinel(); node = node->next) { + s_expression *s_sig = (s_expression *) node; read_function_sig(f, s_sig, skip_body); } return added ? f : NULL; } +static bool +always_available(const _mesa_glsl_parse_state *) +{ + return true; +} + void ir_reader::read_function_sig(ir_function *f, s_expression *expr, bool skip_body) { @@ -241,20 +249,25 @@ ir_reader::read_function_sig(ir_function *f, s_expression *expr, bool skip_body) exec_list hir_parameters; state->symbols->push_scope(); - exec_list_iterator it = paramlist->subexpressions.iterator(); - for (it.next() /* skip "parameters" */; it.has_next(); it.next()) { - ir_variable *var = read_declaration((s_expression *) it.get()); + /* Skip over the "parameters" tag. */ + exec_node *node = paramlist->subexpressions.head->next; + for (/* nothing */; !node->is_tail_sentinel(); node = node->next) { + ir_variable *var = read_declaration((s_expression *) node); if (var == NULL) return; hir_parameters.push_tail(var); } - ir_function_signature *sig = f->exact_matching_signature(&hir_parameters); + ir_function_signature *sig = + f->exact_matching_signature(state, &hir_parameters); if (sig == NULL && skip_body) { /* If scanning for prototypes, generate a new signature. */ - sig = new(mem_ctx) ir_function_signature(return_type); - sig->is_builtin = true; + /* ir_reader doesn't know what languages support a given built-in, so + * just say that they're always available. For now, other mechanisms + * guarantee the right built-ins are available. + */ + sig = new(mem_ctx) ir_function_signature(return_type, always_available); f->add_signature(sig); } else if (sig != NULL) { const char *badvar = sig->qualifiers_match(&hir_parameters); @@ -303,8 +316,7 @@ ir_reader::read_instructions(exec_list *instructions, s_expression *expr, return; } - foreach_iter(exec_list_iterator, it, list->subexpressions) { - s_expression *sub = (s_expression*) it.get(); + foreach_in_list(s_expression, sub, &list->subexpressions) { ir_instruction *ir = read_instruction(sub, loop_ctx); if (ir != NULL) { /* Global variable declarations should be moved to the top, before @@ -353,10 +365,16 @@ ir_reader::read_instruction(s_expression *expr, ir_loop *loop_ctx) inst = read_if(list, loop_ctx); } else if (strcmp(tag->value(), "loop") == 0) { inst = read_loop(list); + } else if (strcmp(tag->value(), "call") == 0) { + inst = read_call(list); } else if (strcmp(tag->value(), "return") == 0) { inst = read_return(list); } else if (strcmp(tag->value(), "function") == 0) { inst = read_function(list, false); + } else if (strcmp(tag->value(), "emit-vertex") == 0) { + inst = read_emit_vertex(list); + } else if (strcmp(tag->value(), "end-primitive") == 0) { + inst = read_end_primitive(list); } else { inst = read_rvalue(list); if (inst == NULL) @@ -385,34 +403,49 @@ ir_reader::read_declaration(s_expression *expr) ir_variable *var = new(mem_ctx) ir_variable(type, s_name->value(), ir_var_auto); - foreach_iter(exec_list_iterator, it, s_quals->subexpressions) { - s_symbol *qualifier = SX_AS_SYMBOL(it.get()); - if (qualifier == NULL) { + foreach_in_list(s_symbol, qualifier, &s_quals->subexpressions) { + if (!qualifier->is_symbol()) { ir_read_error(expr, "qualifier list must contain only symbols"); return NULL; } // FINISHME: Check for duplicate/conflicting qualifiers. if (strcmp(qualifier->value(), "centroid") == 0) { - var->centroid = 1; + var->data.centroid = 1; + } else if (strcmp(qualifier->value(), "sample") == 0) { + var->data.sample = 1; } else if (strcmp(qualifier->value(), "invariant") == 0) { - var->invariant = 1; + var->data.invariant = 1; } else if (strcmp(qualifier->value(), "uniform") == 0) { - var->mode = ir_var_uniform; + var->data.mode = ir_var_uniform; } else if (strcmp(qualifier->value(), "auto") == 0) { - var->mode = ir_var_auto; + var->data.mode = ir_var_auto; } else if (strcmp(qualifier->value(), "in") == 0) { - var->mode = ir_var_in; + var->data.mode = ir_var_function_in; + } else if (strcmp(qualifier->value(), "shader_in") == 0) { + var->data.mode = ir_var_shader_in; + } else if (strcmp(qualifier->value(), "const_in") == 0) { + var->data.mode = ir_var_const_in; } else if (strcmp(qualifier->value(), "out") == 0) { - var->mode = ir_var_out; + var->data.mode = ir_var_function_out; + } else if (strcmp(qualifier->value(), "shader_out") == 0) { + var->data.mode = ir_var_shader_out; } else if (strcmp(qualifier->value(), "inout") == 0) { - var->mode = ir_var_inout; + var->data.mode = ir_var_function_inout; + } else if (strcmp(qualifier->value(), "temporary") == 0) { + var->data.mode = ir_var_temporary; + } else if (strcmp(qualifier->value(), "stream1") == 0) { + var->data.stream = 1; + } else if (strcmp(qualifier->value(), "stream2") == 0) { + var->data.stream = 2; + } else if (strcmp(qualifier->value(), "stream3") == 0) { + var->data.stream = 3; } else if (strcmp(qualifier->value(), "smooth") == 0) { - var->interpolation = ir_var_smooth; + var->data.interpolation = INTERP_QUALIFIER_SMOOTH; } else if (strcmp(qualifier->value(), "flat") == 0) { - var->interpolation = ir_var_flat; + var->data.interpolation = INTERP_QUALIFIER_FLAT; } else if (strcmp(qualifier->value(), "noperspective") == 0) { - var->interpolation = ir_var_noperspective; + var->data.interpolation = INTERP_QUALIFIER_NOPERSPECTIVE; } else { ir_read_error(expr, "unknown qualifier: %s", qualifier->value()); return NULL; @@ -460,18 +493,16 @@ ir_reader::read_if(s_expression *expr, ir_loop *loop_ctx) ir_loop * ir_reader::read_loop(s_expression *expr) { - s_expression *s_counter, *s_from, *s_to, *s_inc, *s_body; + s_expression *s_body; - s_pattern pat[] = { "loop", s_counter, s_from, s_to, s_inc, s_body }; - if (!MATCH(expr, pat)) { - ir_read_error(expr, "expected (loop " - " )"); + s_pattern loop_pat[] = { "loop", s_body }; + if (!MATCH(expr, loop_pat)) { + ir_read_error(expr, "expected (loop )"); return NULL; } - // FINISHME: actually read the count/from/to fields. - ir_loop *loop = new(mem_ctx) ir_loop; + read_instructions(&loop->body_instructions, s_body, loop); if (state->error) { delete loop; @@ -486,19 +517,21 @@ ir_reader::read_return(s_expression *expr) { s_expression *s_retval; - s_pattern pat[] = { "return", s_retval}; - if (!MATCH(expr, pat)) { - ir_read_error(expr, "expected (return )"); - return NULL; - } - - ir_rvalue *retval = read_rvalue(s_retval); - if (retval == NULL) { - ir_read_error(NULL, "when reading return value"); + s_pattern return_value_pat[] = { "return", s_retval}; + s_pattern return_void_pat[] = { "return" }; + if (MATCH(expr, return_value_pat)) { + ir_rvalue *retval = read_rvalue(s_retval); + if (retval == NULL) { + ir_read_error(NULL, "when reading return value"); + return NULL; + } + return new(mem_ctx) ir_return(retval); + } else if (MATCH(expr, return_void_pat)) { + return new(mem_ctx) ir_return; + } else { + ir_read_error(expr, "expected (return ) or (return)"); return NULL; } - - return new(mem_ctx) ir_return(retval); } @@ -522,8 +555,6 @@ ir_reader::read_rvalue(s_expression *expr) rvalue = read_swizzle(list); } else if (strcmp(tag->value(), "expression") == 0) { rvalue = read_expression(list); - } else if (strcmp(tag->value(), "call") == 0) { - rvalue = read_call(list); } else if (strcmp(tag->value(), "constant") == 0) { rvalue = read_constant(list); } else { @@ -611,20 +642,29 @@ ir_reader::read_call(s_expression *expr) { s_symbol *name; s_list *params; + s_list *s_return = NULL; - s_pattern pat[] = { "call", name, params }; - if (!MATCH(expr, pat)) { - ir_read_error(expr, "expected (call ( ...))"); + ir_dereference_variable *return_deref = NULL; + + s_pattern void_pat[] = { "call", name, params }; + s_pattern non_void_pat[] = { "call", name, s_return, params }; + if (MATCH(expr, non_void_pat)) { + return_deref = read_var_ref(s_return); + if (return_deref == NULL) { + ir_read_error(s_return, "when reading a call's return storage"); + return NULL; + } + } else if (!MATCH(expr, void_pat)) { + ir_read_error(expr, "expected (call [] ( ...))"); return NULL; } exec_list parameters; - foreach_iter(exec_list_iterator, it, params->subexpressions) { - s_expression *expr = (s_expression*) it.get(); - ir_rvalue *param = read_rvalue(expr); + foreach_in_list(s_expression, e, ¶ms->subexpressions) { + ir_rvalue *param = read_rvalue(e); if (param == NULL) { - ir_read_error(expr, "when reading parameter to function call"); + ir_read_error(e, "when reading parameter to function call"); return NULL; } parameters.push_tail(param); @@ -637,14 +677,23 @@ ir_reader::read_call(s_expression *expr) return NULL; } - ir_function_signature *callee = f->matching_signature(¶meters); + ir_function_signature *callee = + f->matching_signature(state, ¶meters, true); if (callee == NULL) { ir_read_error(expr, "couldn't find matching signature for function " "%s", name->value()); return NULL; } - return new(mem_ctx) ir_call(callee, ¶meters); + if (callee->return_type == glsl_type::void_type && return_deref) { + ir_read_error(expr, "call has return value storage but void type"); + return NULL; + } else if (callee->return_type != glsl_type::void_type && !return_deref) { + ir_read_error(expr, "call has non-void type but no return value storage"); + return NULL; + } + + return new(mem_ctx) ir_call(callee, return_deref, ¶meters); } ir_expression * @@ -652,15 +701,18 @@ ir_reader::read_expression(s_expression *expr) { s_expression *s_type; s_symbol *s_op; - s_expression *s_arg1; + s_expression *s_arg[4] = {NULL}; - s_pattern pat[] = { "expression", s_type, s_op, s_arg1 }; + s_pattern pat[] = { "expression", s_type, s_op, s_arg[0] }; if (!PARTIAL_MATCH(expr, pat)) { ir_read_error(expr, "expected (expression " - " [])"); + " [] [] [])"); return NULL; } - s_expression *s_arg2 = (s_expression *) s_arg1->next; // may be tail sentinel + s_arg[1] = (s_expression *) s_arg[0]->next; // may be tail sentinel + s_arg[2] = (s_expression *) s_arg[1]->next; // may be tail sentinel or NULL + if (s_arg[2]) + s_arg[3] = (s_expression *) s_arg[2]->next; // may be tail sentinel or NULL const glsl_type *type = read_type(s_type); if (type == NULL) @@ -672,36 +724,27 @@ ir_reader::read_expression(s_expression *expr) ir_read_error(expr, "invalid operator: %s", s_op->value()); return NULL; } - - unsigned num_operands = ir_expression::get_num_operands(op); - if (num_operands == 1 && !s_arg1->next->is_tail_sentinel()) { - ir_read_error(expr, "expected (expression %s )", - s_op->value()); - return NULL; - } - ir_rvalue *arg1 = read_rvalue(s_arg1); - ir_rvalue *arg2 = NULL; - if (arg1 == NULL) { - ir_read_error(NULL, "when reading first operand of %s", s_op->value()); + /* Skip "expression" by subtracting 3. */ + int num_operands = (int) ((s_list *) expr)->subexpressions.length() - 3; + + int expected_operands = ir_expression::get_num_operands(op); + if (num_operands != expected_operands) { + ir_read_error(expr, "found %d expression operands, expected %d", + num_operands, expected_operands); return NULL; } - if (num_operands == 2) { - if (s_arg2->is_tail_sentinel() || !s_arg2->next->is_tail_sentinel()) { - ir_read_error(expr, "expected (expression %s " - ")", s_op->value()); - return NULL; - } - arg2 = read_rvalue(s_arg2); - if (arg2 == NULL) { - ir_read_error(NULL, "when reading second operand of %s", - s_op->value()); - return NULL; + ir_rvalue *arg[4] = {NULL}; + for (int i = 0; i < num_operands; i++) { + arg[i] = read_rvalue(s_arg[i]); + if (arg[i] == NULL) { + ir_read_error(NULL, "when reading operand #%d of %s", i, s_op->value()); + return NULL; } } - return new(mem_ctx) ir_expression(op, type, arg1, arg2); + return new(mem_ctx) ir_expression(op, type, arg[0], arg[1], arg[2], arg[3]); } ir_swizzle * @@ -757,8 +800,7 @@ ir_reader::read_constant(s_expression *expr) if (type->is_array()) { unsigned elements_supplied = 0; exec_list elements; - foreach_iter(exec_list_iterator, it, values->subexpressions) { - s_expression *elt = (s_expression *) it.get(); + foreach_in_list(s_expression, elt, &values->subexpressions) { ir_constant *ir_elt = read_constant(elt); if (ir_elt == NULL) return NULL; @@ -774,21 +816,17 @@ ir_reader::read_constant(s_expression *expr) return new(mem_ctx) ir_constant(type, &elements); } - const glsl_type *const base_type = type->get_base_type(); - ir_constant_data data = { { 0 } }; // Read in list of values (at most 16). - int k = 0; - foreach_iter(exec_list_iterator, it, values->subexpressions) { + unsigned k = 0; + foreach_in_list(s_expression, expr, &values->subexpressions) { if (k >= 16) { ir_read_error(values, "expected at most 16 numbers"); return NULL; } - s_expression *expr = (s_expression*) it.get(); - - if (base_type->base_type == GLSL_TYPE_FLOAT) { + if (type->base_type == GLSL_TYPE_FLOAT) { s_number *value = SX_AS_NUMBER(expr); if (value == NULL) { ir_read_error(values, "expected numbers"); @@ -802,7 +840,7 @@ ir_reader::read_constant(s_expression *expr) return NULL; } - switch (base_type->base_type) { + switch (type->base_type) { case GLSL_TYPE_UINT: { data.u[k] = value->value(); break; @@ -822,21 +860,20 @@ ir_reader::read_constant(s_expression *expr) } ++k; } + if (k != type->components()) { + ir_read_error(values, "expected %u constant values, found %u", + type->components(), k); + return NULL; + } return new(mem_ctx) ir_constant(type, &data); } -ir_dereference * -ir_reader::read_dereference(s_expression *expr) +ir_dereference_variable * +ir_reader::read_var_ref(s_expression *expr) { s_symbol *s_var; - s_expression *s_subject; - s_expression *s_index; - s_symbol *s_field; - s_pattern var_pat[] = { "var_ref", s_var }; - s_pattern array_pat[] = { "array_ref", s_subject, s_index }; - s_pattern record_pat[] = { "record_ref", s_subject, s_field }; if (MATCH(expr, var_pat)) { ir_variable *var = state->symbols->get_variable(s_var->value()); @@ -845,6 +882,23 @@ ir_reader::read_dereference(s_expression *expr) return NULL; } return new(mem_ctx) ir_dereference_variable(var); + } + return NULL; +} + +ir_dereference * +ir_reader::read_dereference(s_expression *expr) +{ + s_expression *s_subject; + s_expression *s_index; + s_symbol *s_field; + + s_pattern array_pat[] = { "array_ref", s_subject, s_index }; + s_pattern record_pat[] = { "record_ref", s_subject, s_field }; + + ir_dereference_variable *var_ref = read_var_ref(expr); + if (var_ref != NULL) { + return var_ref; } else if (MATCH(expr, array_pat)) { ir_rvalue *subject = read_rvalue(s_subject); if (subject == NULL) { @@ -853,7 +907,7 @@ ir_reader::read_dereference(s_expression *expr) } ir_rvalue *idx = read_rvalue(s_index); - if (subject == NULL) { + if (idx == NULL) { ir_read_error(NULL, "when reading the index of an array_ref"); return NULL; } @@ -873,34 +927,68 @@ ir_texture * ir_reader::read_texture(s_expression *expr) { s_symbol *tag = NULL; + s_expression *s_type = NULL; s_expression *s_sampler = NULL; s_expression *s_coord = NULL; - s_list *s_offset = NULL; + s_expression *s_offset = NULL; s_expression *s_proj = NULL; s_list *s_shadow = NULL; s_expression *s_lod = NULL; + s_expression *s_sample_index = NULL; + s_expression *s_component = NULL; - ir_texture_opcode op; + ir_texture_opcode op = ir_tex; /* silence warning */ s_pattern tex_pattern[] = - { "tex", s_sampler, s_coord, s_offset, s_proj, s_shadow }; + { "tex", s_type, s_sampler, s_coord, s_offset, s_proj, s_shadow }; + s_pattern lod_pattern[] = + { "lod", s_type, s_sampler, s_coord }; s_pattern txf_pattern[] = - { "txf", s_sampler, s_coord, s_offset, s_lod }; + { "txf", s_type, s_sampler, s_coord, s_offset, s_lod }; + s_pattern txf_ms_pattern[] = + { "txf_ms", s_type, s_sampler, s_coord, s_sample_index }; + s_pattern txs_pattern[] = + { "txs", s_type, s_sampler, s_lod }; + s_pattern tg4_pattern[] = + { "tg4", s_type, s_sampler, s_coord, s_offset, s_component }; + s_pattern query_levels_pattern[] = + { "query_levels", s_type, s_sampler }; s_pattern other_pattern[] = - { tag, s_sampler, s_coord, s_offset, s_proj, s_shadow, s_lod }; + { tag, s_type, s_sampler, s_coord, s_offset, s_proj, s_shadow, s_lod }; - if (MATCH(expr, tex_pattern)) { + if (MATCH(expr, lod_pattern)) { + op = ir_lod; + } else if (MATCH(expr, tex_pattern)) { op = ir_tex; } else if (MATCH(expr, txf_pattern)) { op = ir_txf; + } else if (MATCH(expr, txf_ms_pattern)) { + op = ir_txf_ms; + } else if (MATCH(expr, txs_pattern)) { + op = ir_txs; + } else if (MATCH(expr, tg4_pattern)) { + op = ir_tg4; + } else if (MATCH(expr, query_levels_pattern)) { + op = ir_query_levels; } else if (MATCH(expr, other_pattern)) { op = ir_texture::get_opcode(tag->value()); - if (op == -1) + if (op == (ir_texture_opcode) -1) return NULL; + } else { + ir_read_error(NULL, "unexpected texture pattern %s", tag->value()); + return NULL; } ir_texture *tex = new(mem_ctx) ir_texture(op); + // Read return type + const glsl_type *type = read_type(s_type); + if (type == NULL) { + ir_read_error(NULL, "when reading type in (%s ...)", + tex->opcode_string()); + return NULL; + } + // Read sampler (must be a deref) ir_dereference *sampler = read_dereference(s_sampler); if (sampler == NULL) { @@ -908,30 +996,33 @@ ir_reader::read_texture(s_expression *expr) tex->opcode_string()); return NULL; } - tex->set_sampler(sampler); + tex->set_sampler(sampler, type); - // Read coordinate (any rvalue) - tex->coordinate = read_rvalue(s_coord); - if (tex->coordinate == NULL) { - ir_read_error(NULL, "when reading coordinate in (%s ...)", - tex->opcode_string()); - return NULL; - } + if (op != ir_txs) { + // Read coordinate (any rvalue) + tex->coordinate = read_rvalue(s_coord); + if (tex->coordinate == NULL) { + ir_read_error(NULL, "when reading coordinate in (%s ...)", + tex->opcode_string()); + return NULL; + } - // Read texel offset, i.e. (0 0 0) - s_int *offset_x; - s_int *offset_y; - s_int *offset_z; - s_pattern offset_pat[] = { offset_x, offset_y, offset_z }; - if (!MATCH(s_offset, offset_pat)) { - ir_read_error(s_offset, "expected ( )"); - return NULL; + if (op != ir_txf_ms && op != ir_lod) { + // Read texel offset - either 0 or an rvalue. + s_int *si_offset = SX_AS_INT(s_offset); + if (si_offset == NULL || si_offset->value() != 0) { + tex->offset = read_rvalue(s_offset); + if (tex->offset == NULL) { + ir_read_error(s_offset, "expected 0 or an expression"); + return NULL; + } + } + } } - tex->offsets[0] = offset_x->value(); - tex->offsets[1] = offset_y->value(); - tex->offsets[2] = offset_z->value(); - if (op != ir_txf) { + if (op != ir_txf && op != ir_txf_ms && + op != ir_txs && op != ir_lod && op != ir_tg4 && + op != ir_query_levels) { s_int *proj_as_int = SX_AS_INT(s_proj); if (proj_as_int && proj_as_int->value() == 1) { tex->projector = NULL; @@ -966,6 +1057,7 @@ ir_reader::read_texture(s_expression *expr) break; case ir_txl: case ir_txf: + case ir_txs: tex->lod_info.lod = read_rvalue(s_lod); if (tex->lod_info.lod == NULL) { ir_read_error(NULL, "when reading LOD in (%s ...)", @@ -973,6 +1065,13 @@ ir_reader::read_texture(s_expression *expr) return NULL; } break; + case ir_txf_ms: + tex->lod_info.sample_index = read_rvalue(s_sample_index); + if (tex->lod_info.sample_index == NULL) { + ir_read_error(NULL, "when reading sample_index in (txf_ms ...)"); + return NULL; + } + break; case ir_txd: { s_expression *s_dx, *s_dy; s_pattern dxdy_pat[] = { s_dx, s_dy }; @@ -992,9 +1091,54 @@ ir_reader::read_texture(s_expression *expr) } break; } + case ir_tg4: + tex->lod_info.component = read_rvalue(s_component); + if (tex->lod_info.component == NULL) { + ir_read_error(NULL, "when reading component in (tg4 ...)"); + return NULL; + } + break; default: - // tex doesn't have any extra parameters. + // tex and lod don't have any extra parameters. break; }; return tex; } + +ir_emit_vertex * +ir_reader::read_emit_vertex(s_expression *expr) +{ + s_expression *s_stream = NULL; + + s_pattern pat[] = { "emit-vertex", s_stream }; + + if (MATCH(expr, pat)) { + ir_rvalue *stream = read_dereference(s_stream); + if (stream == NULL) { + ir_read_error(NULL, "when reading stream info in emit-vertex"); + return NULL; + } + return new(mem_ctx) ir_emit_vertex(stream); + } + ir_read_error(NULL, "when reading emit-vertex"); + return NULL; +} + +ir_end_primitive * +ir_reader::read_end_primitive(s_expression *expr) +{ + s_expression *s_stream = NULL; + + s_pattern pat[] = { "end-primitive", s_stream }; + + if (MATCH(expr, pat)) { + ir_rvalue *stream = read_dereference(s_stream); + if (stream == NULL) { + ir_read_error(NULL, "when reading stream info in end-primitive"); + return NULL; + } + return new(mem_ctx) ir_end_primitive(stream); + } + ir_read_error(NULL, "when reading end-primitive"); + return NULL; +}