diff --git a/src/glsl/ast.h b/src/glsl/ast.h index ef74e51..4921229 100644 --- a/src/glsl/ast.h +++ b/src/glsl/ast.h @@ -435,6 +435,7 @@ struct ast_type_qualifier { unsigned centroid:1; unsigned sample:1; unsigned uniform:1; + unsigned buffer:1; unsigned smooth:1; unsigned flat:1; unsigned noperspective:1; diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp index d387b2e..e65b362 100644 --- a/src/glsl/ast_to_hir.cpp +++ b/src/glsl/ast_to_hir.cpp @@ -2534,6 +2534,8 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, var->data.mode = ir_var_shader_out; else if (qual->flags.q.uniform) var->data.mode = ir_var_uniform; + else if (qual->flags.q.buffer) + var->data.mode = ir_var_uniform; if (!is_parameter && is_varying_var(var, state->stage)) { /* User-defined ins/outs are not permitted in compute shaders. */ @@ -2690,7 +2692,7 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, } if (var->type->contains_atomic()) { - if (var->data.mode == ir_var_uniform) { + if (var->data.mode == ir_var_uniform || var->data.mode == ir_var_buffer) { if (var->data.explicit_binding) { unsigned *offset = &state->atomic_counter_offsets[var->data.binding]; @@ -2708,8 +2710,8 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, } } else if (var->data.mode != ir_var_function_in) { _mesa_glsl_error(loc, state, "atomic counters may only be declared as " - "function parameters or uniform-qualified " - "global variables"); + "function parameters, uniform-qualified or " + "buffer-qualified global variables"); } } @@ -5192,8 +5194,9 @@ ast_type_specifier::hir(exec_list *instructions, * \c glsl_struct_field to describe the members. * * If we're processing an interface block, var_mode should be the type of the - * interface block (ir_var_shader_in, ir_var_shader_out, or ir_var_uniform). - * If we're processing a structure, var_mode should be ir_var_auto. + * interface block (ir_var_shader_in, ir_var_shader_out, ir_var_uniform or + * ir_var_buffer). If we're processing a structure, var_mode should be + * ir_var_auto. * * \return * The number of fields processed. A pointer to the array structure fields is @@ -5323,10 +5326,10 @@ ast_process_structure_or_interface_block(exec_list *instructions, fields[i].stream = qual->flags.q.explicit_stream ? qual->stream : -1; if (qual->flags.q.row_major || qual->flags.q.column_major) { - if (!qual->flags.q.uniform) { + if (!qual->flags.q.uniform && !qual->flags.q.buffer) { _mesa_glsl_error(&loc, state, "row_major and column_major can only be " - "applied to uniform interface blocks"); + "applied to interface blocks"); } else validate_matrix_layout_for_type(state, &loc, field_type, NULL); } @@ -5523,6 +5526,9 @@ ast_interface_block::hir(exec_list *instructions, } else if (this->layout.flags.q.uniform) { var_mode = ir_var_uniform; iface_type_name = "uniform"; + } else if (this->layout.flags.q.buffer) { + var_mode = ir_var_buffer; + iface_type_name = "buffer"; } else { var_mode = ir_var_auto; iface_type_name = "UNKNOWN"; diff --git a/src/glsl/ast_type.cpp b/src/glsl/ast_type.cpp index b596cd5..820b3ae 100644 --- a/src/glsl/ast_type.cpp +++ b/src/glsl/ast_type.cpp @@ -78,7 +78,8 @@ ast_type_qualifier::has_storage() const || this->flags.q.varying || this->flags.q.in || this->flags.q.out - || this->flags.q.uniform; + || this->flags.q.uniform + || this->flags.q.buffer; } bool diff --git a/src/glsl/builtin_variables.cpp b/src/glsl/builtin_variables.cpp index 21e7331..9d7dfe2 100644 --- a/src/glsl/builtin_variables.cpp +++ b/src/glsl/builtin_variables.cpp @@ -436,11 +436,12 @@ builtin_variable_generator::add_variable(const char *name, var->data.read_only = true; break; case ir_var_shader_out: + case ir_var_buffer: break; default: /* The only variables that are added using this function should be - * uniforms, shader inputs, and shader outputs, constants (which use - * ir_var_auto), and system values. + * uniforms, buffers, shader inputs, and shader outputs, constants + * (which use ir_var_auto), and system values. */ assert(0); break; diff --git a/src/glsl/glsl_lexer.ll b/src/glsl/glsl_lexer.ll index 8dc3d10..13a048b 100644 --- a/src/glsl/glsl_lexer.ll +++ b/src/glsl/glsl_lexer.ll @@ -292,6 +292,7 @@ in return IN_TOK; out return OUT_TOK; inout return INOUT_TOK; uniform return UNIFORM; +buffer return BUFFER; varying DEPRECATED_ES_KEYWORD(VARYING); centroid KEYWORD(120, 300, 120, 300, CENTROID); invariant KEYWORD(120, 100, 120, 100, INVARIANT); diff --git a/src/glsl/glsl_parser.yy b/src/glsl/glsl_parser.yy index 90c216e..0161016 100644 --- a/src/glsl/glsl_parser.yy +++ b/src/glsl/glsl_parser.yy @@ -130,7 +130,7 @@ static bool match_layout_qualifier(const char *s1, const char *s2, } %token ATTRIBUTE CONST_TOK BOOL_TOK FLOAT_TOK INT_TOK UINT_TOK DOUBLE_TOK -%token BREAK CONTINUE DO ELSE FOR IF DISCARD RETURN SWITCH CASE DEFAULT +%token BREAK BUFFER CONTINUE DO ELSE FOR IF DISCARD RETURN SWITCH CASE DEFAULT %token BVEC2 BVEC3 BVEC4 IVEC2 IVEC3 IVEC4 UVEC2 UVEC3 UVEC4 VEC2 VEC3 VEC4 DVEC2 DVEC3 DVEC4 %token CENTROID IN_TOK OUT_TOK INOUT_TOK UNIFORM VARYING SAMPLE %token NOPERSPECTIVE FLAT SMOOTH @@ -1774,6 +1774,11 @@ storage_qualifier: memset(& $$, 0, sizeof($$)); $$.flags.q.uniform = 1; } + | BUFFER + { + memset(& $$, 0, sizeof($$)); + $$.flags.q.buffer = 1; + } | COHERENT { memset(& $$, 0, sizeof($$)); @@ -2473,7 +2478,9 @@ basic_interface_block: block->block_name = $2; block->declarations.push_degenerate_list_at_head(& $4->link); - if ($1.flags.q.uniform) { + if ($1.flags.q.buffer) { + /* buffer checks here */ + } else if ($1.flags.q.uniform) { if (!state->has_uniform_buffer_objects()) { _mesa_glsl_error(& @1, state, "#version 140 / GL_ARB_uniform_buffer_object " @@ -2517,11 +2524,13 @@ basic_interface_block: uint64_t interface_type_mask; struct ast_type_qualifier temp_type_qualifier; - /* Get a bitmask containing only the in/out/uniform flags, allowing us - * to ignore other irrelevant flags like interpolation qualifiers. + /* Get a bitmask containing only the in/out/uniform/buffer + * flags, allowing us to ignore other irrelevant flags like + * interpolation qualifiers. */ temp_type_qualifier.flags.i = 0; temp_type_qualifier.flags.q.uniform = true; + temp_type_qualifier.flags.q.buffer = true; temp_type_qualifier.flags.q.in = true; temp_type_qualifier.flags.q.out = true; interface_type_mask = temp_type_qualifier.flags.i; @@ -2608,6 +2617,11 @@ interface_qualifier: memset(& $$, 0, sizeof($$)); $$.flags.q.uniform = 1; } + | BUFFER + { + memset(& $$, 0, sizeof($$)); + $$.flags.q.buffer = 1; + } ; instance_name_opt: diff --git a/src/glsl/glsl_parser_extras.cpp b/src/glsl/glsl_parser_extras.cpp index 79624bc..13b5a45 100644 --- a/src/glsl/glsl_parser_extras.cpp +++ b/src/glsl/glsl_parser_extras.cpp @@ -834,6 +834,8 @@ _mesa_ast_type_qualifier_print(const struct ast_type_qualifier *q) printf("sample "); if (q->flags.q.uniform) printf("uniform "); + if (q->flags.q.buffer) + printf("buffer "); if (q->flags.q.smooth) printf("smooth "); if (q->flags.q.flat) diff --git a/src/glsl/glsl_symbol_table.cpp b/src/glsl/glsl_symbol_table.cpp index 2294dda..e557689 100644 --- a/src/glsl/glsl_symbol_table.cpp +++ b/src/glsl/glsl_symbol_table.cpp @@ -36,6 +36,9 @@ public: case ir_var_uniform: dest = &ibu; break; + case ir_var_buffer: + dest = &ibb; + break; case ir_var_shader_in: dest = &ibi; break; @@ -60,6 +63,8 @@ public: switch (mode) { case ir_var_uniform: return ibu; + case ir_var_buffer: + return ibb; case ir_var_shader_in: return ibi; case ir_var_shader_out: @@ -71,24 +76,25 @@ public: } symbol_table_entry(ir_variable *v) : - v(v), f(0), t(0), ibu(0), ibi(0), ibo(0), a(0) {} + v(v), f(0), t(0), ibu(0), ibb(0), ibi(0), ibo(0), a(0) {} symbol_table_entry(ir_function *f) : - v(0), f(f), t(0), ibu(0), ibi(0), ibo(0), a(0) {} + v(0), f(f), t(0), ibu(0), ibb(0), ibi(0), ibo(0), a(0) {} symbol_table_entry(const glsl_type *t) : - v(0), f(0), t(t), ibu(0), ibi(0), ibo(0), a(0) {} + v(0), f(0), t(t), ibu(0), ibb(0), ibi(0), ibo(0), a(0) {} symbol_table_entry(const glsl_type *t, enum ir_variable_mode mode) : - v(0), f(0), t(0), ibu(0), ibi(0), ibo(0), a(0) + v(0), f(0), t(0), ibu(0), ibb(0), ibi(0), ibo(0), a(0) { assert(t->is_interface()); add_interface(t, mode); } symbol_table_entry(const class ast_type_specifier *a): - v(0), f(0), t(0), ibu(0), ibi(0), ibo(0), a(a) {} + v(0), f(0), t(0), ibu(0), ibb(0), ibi(0), ibo(0), a(a) {} ir_variable *v; ir_function *f; const glsl_type *t; const glsl_type *ibu; + const glsl_type *ibb; const glsl_type *ibi; const glsl_type *ibo; const class ast_type_specifier *a; diff --git a/src/glsl/ir.cpp b/src/glsl/ir.cpp index 54656f8..d88bc26 100644 --- a/src/glsl/ir.cpp +++ b/src/glsl/ir.cpp @@ -602,6 +602,8 @@ static const char *const operator_strs[] = { "packHalf2x16_split", "bfm", "ubo_load", + "ssbo_load", + "ssbo_store", "ldexp", "vector_extract", "interpolate_at_offset", @@ -1977,6 +1979,9 @@ mode_string(const ir_variable *var) case ir_var_uniform: return "uniform"; + case ir_var_buffer: + return "buffer"; + case ir_var_shader_in: return "shader input"; diff --git a/src/glsl/ir.h b/src/glsl/ir.h index 25f2eca..2322201 100644 --- a/src/glsl/ir.h +++ b/src/glsl/ir.h @@ -305,6 +305,7 @@ protected: enum ir_variable_mode { ir_var_auto = 0, /**< Function local variables and globals. */ ir_var_uniform, /**< Variable declared as a uniform. */ + ir_var_buffer, /**< Variable declared as an ssbo. */ ir_var_shader_in, ir_var_shader_out, ir_var_function_in, @@ -426,7 +427,8 @@ public: */ inline bool is_in_uniform_block() const { - return this->data.mode == ir_var_uniform && this->interface_type != NULL; + return (this->data.mode == ir_var_uniform || + this->data.mode == ir_var_buffer) && this->interface_type != NULL; } /** @@ -1477,6 +1479,24 @@ enum ir_expression_operation { ir_binop_ubo_load, /** + * Load a value the size of a given GLSL type from a buffer block. + * + * operand0 is the ir_constant buffer block index in the linked shader. + * operand1 is a byte offset within the uniform block. + */ + ir_binop_ssbo_load, + + /** + * Store a value the size of a given GLSL type to a buffer block. + * + * operand0 is the ir_constant buffer block index in the linked shader. + * operand1 is a byte offset within the uniform block. + * operand2 is the value. + */ + ir_binop_ssbo_store, + + + /** * \name Multiplies a number by two to a power, part of ARB_gpu_shader5. */ /*@{*/ diff --git a/src/glsl/ir_function.cpp b/src/glsl/ir_function.cpp index 2b2643c..d6f2167 100644 --- a/src/glsl/ir_function.cpp +++ b/src/glsl/ir_function.cpp @@ -72,6 +72,7 @@ parameter_lists_match(_mesa_glsl_parse_state *state, switch ((enum ir_variable_mode)(param->data.mode)) { case ir_var_auto: case ir_var_uniform: + case ir_var_buffer: case ir_var_temporary: /* These are all error conditions. It is invalid for a parameter to * a function to be declared as auto (not in, out, or inout) or diff --git a/src/glsl/ir_print_visitor.cpp b/src/glsl/ir_print_visitor.cpp index 01f52e8..ce411f2 100644 --- a/src/glsl/ir_print_visitor.cpp +++ b/src/glsl/ir_print_visitor.cpp @@ -164,7 +164,8 @@ void ir_print_visitor::visit(ir_variable *ir) const char *const cent = (ir->data.centroid) ? "centroid " : ""; const char *const samp = (ir->data.sample) ? "sample " : ""; const char *const inv = (ir->data.invariant) ? "invariant " : ""; - const char *const mode[] = { "", "uniform ", "shader_in ", "shader_out ", + const char *const mode[] = { "", "uniform ", "buffer", + "shader_in ", "shader_out ", "in ", "out ", "inout ", "const_in ", "sys ", "temporary " }; STATIC_ASSERT(ARRAY_SIZE(mode) == ir_var_mode_count); diff --git a/src/glsl/ir_reader.cpp b/src/glsl/ir_reader.cpp index fd318c0..ff62130 100644 --- a/src/glsl/ir_reader.cpp +++ b/src/glsl/ir_reader.cpp @@ -418,6 +418,8 @@ ir_reader::read_declaration(s_expression *expr) var->data.invariant = 1; } else if (strcmp(qualifier->value(), "uniform") == 0) { var->data.mode = ir_var_uniform; + } else if (strcmp(qualifier->value(), "buffer") == 0) { + var->data.mode = ir_var_buffer; } else if (strcmp(qualifier->value(), "auto") == 0) { var->data.mode = ir_var_auto; } else if (strcmp(qualifier->value(), "in") == 0) { diff --git a/src/glsl/ir_validate.cpp b/src/glsl/ir_validate.cpp index 7a7688c..340832d 100644 --- a/src/glsl/ir_validate.cpp +++ b/src/glsl/ir_validate.cpp @@ -575,6 +575,16 @@ ir_validate::visit_leave(ir_expression *ir) assert(ir->operands[1]->type == glsl_type::uint_type); break; + case ir_binop_ssbo_load: + assert(ir->operands[0]->type == glsl_type::uint_type); + assert(ir->operands[1]->type == glsl_type::uint_type); + break; + + case ir_binop_ssbo_store: + assert(ir->operands[0]->type == glsl_type::uint_type); + assert(ir->operands[1]->type == glsl_type::uint_type); + break; + case ir_binop_ldexp: assert(ir->operands[0]->type == ir->type); assert(ir->operands[0]->type->is_float() || diff --git a/src/glsl/link_interface_blocks.cpp b/src/glsl/link_interface_blocks.cpp index 07f5b42..6e919ba 100644 --- a/src/glsl/link_interface_blocks.cpp +++ b/src/glsl/link_interface_blocks.cpp @@ -112,7 +112,8 @@ intrastage_match(interface_block_definition *a, * it's not clear from the spec whether they need to match, but * Mesa's implementation relies on them matching. */ - if (a->instance_name != NULL && mode != ir_var_uniform && + if (a->instance_name != NULL && + mode != ir_var_uniform && mode != ir_var_buffer && strcmp(a->instance_name, b->instance_name) != 0) { return false; } @@ -253,6 +254,7 @@ validate_intrastage_interface_blocks(struct gl_shader_program *prog, interface_block_definitions in_interfaces; interface_block_definitions out_interfaces; interface_block_definitions uniform_interfaces; + interface_block_definitions buffer_interfaces; for (unsigned int i = 0; i < num_shaders; i++) { if (shader_list[i] == NULL) @@ -279,6 +281,9 @@ validate_intrastage_interface_blocks(struct gl_shader_program *prog, case ir_var_uniform: definitions = &uniform_interfaces; break; + case ir_var_buffer: + definitions = &buffer_interfaces; + break; default: /* Only in, out, and uniform interfaces are legal, so we should * never get here. @@ -361,7 +366,9 @@ validate_interstage_uniform_blocks(struct gl_shader_program *prog, const gl_shader *stage = stages[i]; foreach_in_list(ir_instruction, node, stage->ir) { ir_variable *var = node->as_variable(); - if (!var || !var->get_interface_type() || var->data.mode != ir_var_uniform) + if (!var || !var->get_interface_type() || + var->data.mode != ir_var_uniform || + var->data.mode != ir_var_buffer) continue; interface_block_definition *old_def = diff --git a/src/glsl/link_uniform_block_active_visitor.h b/src/glsl/link_uniform_block_active_visitor.h index e5ea501..311c5d5 100644 --- a/src/glsl/link_uniform_block_active_visitor.h +++ b/src/glsl/link_uniform_block_active_visitor.h @@ -38,6 +38,7 @@ struct link_uniform_block_active { bool has_instance_name; bool has_binding; + bool is_buffer; }; class link_uniform_block_active_visitor : public ir_hierarchical_visitor { diff --git a/src/glsl/link_uniform_initializers.cpp b/src/glsl/link_uniform_initializers.cpp index 6907384..051cb8e 100644 --- a/src/glsl/link_uniform_initializers.cpp +++ b/src/glsl/link_uniform_initializers.cpp @@ -256,7 +256,8 @@ link_set_uniform_initializers(struct gl_shader_program *prog, foreach_in_list(ir_instruction, node, shader->ir) { ir_variable *const var = node->as_variable(); - if (!var || var->data.mode != ir_var_uniform) + if (!var || var->data.mode != ir_var_uniform || + var->data.mode != ir_var_buffer) continue; if (!mem_ctx) diff --git a/src/glsl/link_uniforms.cpp b/src/glsl/link_uniforms.cpp index 799c74b..ac96a7d 100644 --- a/src/glsl/link_uniforms.cpp +++ b/src/glsl/link_uniforms.cpp @@ -756,7 +756,8 @@ link_update_uniform_buffer_variables(struct gl_shader *shader) if ((var == NULL) || !var->is_in_uniform_block()) continue; - assert(var->data.mode == ir_var_uniform); + assert(var->data.mode == ir_var_uniform || + var->data.mode == ir_var_buffer); if (var->is_interface_instance()) { var->data.location = 0; @@ -933,7 +934,8 @@ link_assign_uniform_locations(struct gl_shader_program *prog, foreach_in_list(ir_instruction, node, sh->ir) { ir_variable *const var = node->as_variable(); - if ((var == NULL) || (var->data.mode != ir_var_uniform)) + if ((var == NULL) || (var->data.mode != ir_var_uniform && + var->data.mode != ir_var_buffer)) continue; /* FINISHME: Update code to process built-in uniforms! @@ -985,7 +987,7 @@ link_assign_uniform_locations(struct gl_shader_program *prog, foreach_in_list(ir_instruction, node, prog->_LinkedShaders[i]->ir) { ir_variable *const var = node->as_variable(); - if ((var == NULL) || (var->data.mode != ir_var_uniform)) + if ((var == NULL) || (var->data.mode != ir_var_uniform && var->data.mode != ir_var_buffer)) continue; /* FINISHME: Update code to process built-in uniforms! diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp index 0c44677..245aea0 100644 --- a/src/glsl/linker.cpp +++ b/src/glsl/linker.cpp @@ -744,7 +744,7 @@ cross_validate_globals(struct gl_shader_program *prog, if (var == NULL) continue; - if (uniforms_only && (var->data.mode != ir_var_uniform)) + if (uniforms_only && (var->data.mode != ir_var_uniform && var->data.mode != ir_var_buffer)) continue; /* Don't cross validate temporaries that are at global scope. These @@ -2490,7 +2490,7 @@ check_explicit_uniform_locations(struct gl_context *ctx, foreach_in_list(ir_instruction, node, sh->ir) { ir_variable *var = node->as_variable(); - if ((var && var->data.mode == ir_var_uniform) && + if (var && (var->data.mode == ir_var_uniform || var->data.mode == ir_var_buffer) && var->data.explicit_location) { if (!reserve_explicit_locations(prog, uniform_map, var)) { delete uniform_map; diff --git a/src/glsl/loop_unroll.cpp b/src/glsl/loop_unroll.cpp index 635e1dd..de70deb 100644 --- a/src/glsl/loop_unroll.cpp +++ b/src/glsl/loop_unroll.cpp @@ -133,6 +133,7 @@ public: unsupported_variable_indexing = true; break; case ir_var_uniform: + case ir_var_buffer: if (options->EmitNoIndirectUniform) unsupported_variable_indexing = true; break; diff --git a/src/glsl/lower_named_interface_blocks.cpp b/src/glsl/lower_named_interface_blocks.cpp index 7304c51..72b4f4a 100644 --- a/src/glsl/lower_named_interface_blocks.cpp +++ b/src/glsl/lower_named_interface_blocks.cpp @@ -108,7 +108,8 @@ flatten_named_interface_blocks_declarations::run(exec_list *instructions) * but, this will require changes to the other uniform block * support code. */ - if (var->data.mode == ir_var_uniform) + if (var->data.mode == ir_var_uniform || + var->data.mode == ir_var_buffer) continue; const glsl_type * iface_t = var->type; @@ -212,7 +213,7 @@ flatten_named_interface_blocks_declarations::handle_rvalue(ir_rvalue **rvalue) * but, this will require changes to the other uniform block * support code. */ - if (var->data.mode == ir_var_uniform) + if (var->data.mode == ir_var_uniform || var->data.mode == ir_var_buffer) return; if (var->get_interface_type() != NULL) { diff --git a/src/glsl/lower_ubo_reference.cpp b/src/glsl/lower_ubo_reference.cpp index 4ea4ccb..fb8a890 100644 --- a/src/glsl/lower_ubo_reference.cpp +++ b/src/glsl/lower_ubo_reference.cpp @@ -149,6 +149,7 @@ public: struct gl_shader *shader; struct gl_uniform_buffer_variable *ubo_var; ir_rvalue *uniform_block; + enum ir_expression_operation opcode; bool progress; }; @@ -252,6 +253,11 @@ lower_ubo_reference_visitor::handle_rvalue(ir_rvalue **rvalue) this->uniform_block = index; } + if (shader->UniformBlocks[i].IsBuffer) + this->opcode = ir_binop_ssbo_load; + else + this->opcode = ir_binop_ubo_load; + struct gl_uniform_block *block = &shader->UniformBlocks[i]; this->ubo_var = var->is_interface_instance() @@ -413,7 +419,7 @@ lower_ubo_reference_visitor::ubo_load(const glsl_type *type, { ir_rvalue *block_ref = this->uniform_block->clone(mem_ctx, NULL); return new(mem_ctx) - ir_expression(ir_binop_ubo_load, + ir_expression(this->opcode, type, block_ref, offset); diff --git a/src/glsl/lower_variable_index_to_cond_assign.cpp b/src/glsl/lower_variable_index_to_cond_assign.cpp index d878cb0..80706a7 100644 --- a/src/glsl/lower_variable_index_to_cond_assign.cpp +++ b/src/glsl/lower_variable_index_to_cond_assign.cpp @@ -370,6 +370,7 @@ public: case ir_var_temporary: return this->lower_temps; case ir_var_uniform: + case ir_var_buffer: return this->lower_uniforms; case ir_var_function_in: case ir_var_const_in: diff --git a/src/glsl/opt_structure_splitting.cpp b/src/glsl/opt_structure_splitting.cpp index 5e82fe9..f85ab50 100644 --- a/src/glsl/opt_structure_splitting.cpp +++ b/src/glsl/opt_structure_splitting.cpp @@ -103,8 +103,9 @@ ir_structure_reference_visitor::get_variable_entry(ir_variable *var) { assert(var); - if (!var->type->is_record() || var->data.mode == ir_var_uniform - || var->data.mode == ir_var_shader_in || var->data.mode == ir_var_shader_out) + if (!var->type->is_record() || + var->data.mode == ir_var_uniform || var->data.mode == ir_var_buffer || + var->data.mode == ir_var_shader_in || var->data.mode == ir_var_shader_out) return NULL; foreach_in_list(variable_entry, entry, &this->variable_list) { diff --git a/src/mesa/drivers/dri/i965/brw_fs.cpp b/src/mesa/drivers/dri/i965/brw_fs.cpp index 8702ea8..da92fcc 100644 --- a/src/mesa/drivers/dri/i965/brw_fs.cpp +++ b/src/mesa/drivers/dri/i965/brw_fs.cpp @@ -506,6 +506,7 @@ fs_inst::is_send_from_grf() const case SHADER_OPCODE_UNTYPED_ATOMIC: case SHADER_OPCODE_UNTYPED_SURFACE_READ: case SHADER_OPCODE_URB_WRITE_SIMD8: + case SHADER_OPCODE_BUFFER_LOAD: return true; case FS_OPCODE_UNIFORM_PULL_CONSTANT_LOAD: return src[1].file == GRF; @@ -1031,6 +1032,7 @@ fs_visitor::implied_mrf_writes(fs_inst *inst) return 2; case FS_OPCODE_UNIFORM_PULL_CONSTANT_LOAD: case SHADER_OPCODE_GEN4_SCRATCH_READ: + case SHADER_OPCODE_BUFFER_LOAD: return 1; case FS_OPCODE_VARYING_PULL_CONSTANT_LOAD: return inst->mlen; diff --git a/src/mesa/drivers/dri/i965/brw_fs.h b/src/mesa/drivers/dri/i965/brw_fs.h index 7716529..e4e9ba2 100644 --- a/src/mesa/drivers/dri/i965/brw_fs.h +++ b/src/mesa/drivers/dri/i965/brw_fs.h @@ -578,6 +578,12 @@ private: struct brw_reg dst, struct brw_reg index, struct brw_reg offset); + + void generate_buffer_load(fs_inst *inst, + struct brw_reg dst, + struct brw_reg index, + struct brw_reg offset); + void generate_mov_dispatch_to_flags(fs_inst *inst); void generate_pixel_interpolator_query(fs_inst *inst, diff --git a/src/mesa/drivers/dri/i965/brw_fs_channel_expressions.cpp b/src/mesa/drivers/dri/i965/brw_fs_channel_expressions.cpp index 933fdde..899555a 100644 --- a/src/mesa/drivers/dri/i965/brw_fs_channel_expressions.cpp +++ b/src/mesa/drivers/dri/i965/brw_fs_channel_expressions.cpp @@ -383,6 +383,8 @@ ir_channel_expressions_visitor::visit_leave(ir_assignment *ir) } case ir_binop_ubo_load: + case ir_binop_ssbo_load: + case ir_binop_ssbo_store: unreachable("not yet supported"); case ir_triop_fma: diff --git a/src/mesa/drivers/dri/i965/brw_fs_generator.cpp b/src/mesa/drivers/dri/i965/brw_fs_generator.cpp index e086266..e9347b9 100644 --- a/src/mesa/drivers/dri/i965/brw_fs_generator.cpp +++ b/src/mesa/drivers/dri/i965/brw_fs_generator.cpp @@ -1012,6 +1012,26 @@ fs_generator::generate_uniform_pull_constant_load(fs_inst *inst, } void +fs_generator::generate_buffer_load(fs_inst *inst, + struct brw_reg dst, + struct brw_reg index, + struct brw_reg offset) +{ + assert(index.file == BRW_IMMEDIATE_VALUE && + index.type == BRW_REGISTER_TYPE_UD); + uint32_t surf_index = index.dw1.ud; + + assert(offset.file == BRW_IMMEDIATE_VALUE && + offset.type == BRW_REGISTER_TYPE_UD); + uint32_t read_offset = offset.dw1.ud; + + brw_oword_block_read(p, dst, brw_message_reg(inst->base_mrf), + read_offset, surf_index); + + brw_mark_surface_used(prog_data, surf_index); +} + +void fs_generator::generate_uniform_pull_constant_load_gen7(fs_inst *inst, struct brw_reg dst, struct brw_reg index, @@ -2018,6 +2038,10 @@ fs_generator::generate_code(const cfg_t *cfg, int dispatch_width) generate_untyped_surface_read(inst, dst, src[0], src[1]); break; + case SHADER_OPCODE_BUFFER_LOAD: + generate_buffer_load(inst, dst, src[0], src[1]); + break; + case FS_OPCODE_SET_SIMD4X2_OFFSET: generate_set_simd4x2_offset(inst, dst, src[0]); break; diff --git a/src/mesa/drivers/dri/i965/brw_fs_visitor.cpp b/src/mesa/drivers/dri/i965/brw_fs_visitor.cpp index 5d4b166..4c83748 100644 --- a/src/mesa/drivers/dri/i965/brw_fs_visitor.cpp +++ b/src/mesa/drivers/dri/i965/brw_fs_visitor.cpp @@ -1094,6 +1094,8 @@ fs_visitor::visit(ir_expression *ir) case ir_binop_pack_half_2x16_split: emit(FS_OPCODE_PACK_HALF_2x16_SPLIT, this->result, op[0], op[1]); break; + + case ir_binop_ssbo_load: case ir_binop_ubo_load: { /* This IR node takes a constant uniform block and a constant or * variable byte offset within the block and loads a vector from that. @@ -1129,9 +1131,15 @@ fs_visitor::visit(ir_expression *ir) if (const_offset) { fs_reg packed_consts = vgrf(glsl_type::float_type); packed_consts.type = result.type; + enum opcode opcode; + + if (ir->operation == ir_binop_ssbo_load) + opcode = SHADER_OPCODE_BUFFER_LOAD; + else + opcode = FS_OPCODE_UNIFORM_PULL_CONSTANT_LOAD; fs_reg const_offset_reg = fs_reg(const_offset->value.u[0] & ~15); - emit(new(mem_ctx) fs_inst(FS_OPCODE_UNIFORM_PULL_CONSTANT_LOAD, 8, + emit(new(mem_ctx) fs_inst(opcode, 8, packed_consts, surf_index, const_offset_reg)); for (int i = 0; i < ir->type->vector_elements; i++) { @@ -1158,6 +1166,9 @@ fs_visitor::visit(ir_expression *ir) fs_reg base_offset = vgrf(glsl_type::int_type); emit(SHR(base_offset, op[1], fs_reg(2))); + if (ir->operation == ir_binop_ssbo_load) + assert(!"Not implemented"); + for (int i = 0; i < ir->type->vector_elements; i++) { emit(VARYING_PULL_CONSTANT_LOAD(result, surf_index, base_offset, i)); @@ -1173,6 +1184,10 @@ fs_visitor::visit(ir_expression *ir) break; } + case ir_binop_ssbo_store: + assert(!"Not implemented"); + break; + case ir_triop_fma: /* Note that the instruction's argument order is reversed from GLSL * and the IR. @@ -2499,7 +2514,8 @@ fs_visitor::emit_bool_to_cond_code(ir_rvalue *ir) { ir_expression *expr = ir->as_expression(); - if (!expr || expr->operation == ir_binop_ubo_load) { + if (!expr || expr->operation == ir_binop_ubo_load || + expr->operation == ir_binop_ssbo_load) { ir->accept(this); fs_inst *inst = emit(AND(reg_null_d, this->result, fs_reg(1))); @@ -2624,7 +2640,8 @@ fs_visitor::emit_if_gen6(ir_if *ir) { ir_expression *expr = ir->condition->as_expression(); - if (expr && expr->operation != ir_binop_ubo_load) { + if (expr && expr->operation != ir_binop_ubo_load && + expr->operation != ir_binop_ssbo_load) { fs_reg op[3]; fs_inst *inst; fs_reg temp; diff --git a/src/mesa/drivers/dri/i965/brw_schedule_instructions.cpp b/src/mesa/drivers/dri/i965/brw_schedule_instructions.cpp index 56f69ea..5354f4a 100644 --- a/src/mesa/drivers/dri/i965/brw_schedule_instructions.cpp +++ b/src/mesa/drivers/dri/i965/brw_schedule_instructions.cpp @@ -358,6 +358,7 @@ schedule_node::set_latency_gen7(bool is_haswell) break; case SHADER_OPCODE_UNTYPED_SURFACE_READ: + case SHADER_OPCODE_BUFFER_LOAD: /* Test code: * mov(8) g112<1>UD 0x00000000UD { align1 WE_all 1Q }; * mov(1) g112.7<1>UD g1.7<0,1,0>UD { align1 WE_all }; diff --git a/src/mesa/drivers/dri/i965/brw_shader.cpp b/src/mesa/drivers/dri/i965/brw_shader.cpp index 51c965c..940858d 100644 --- a/src/mesa/drivers/dri/i965/brw_shader.cpp +++ b/src/mesa/drivers/dri/i965/brw_shader.cpp @@ -456,6 +456,8 @@ brw_instruction_name(enum opcode op) return "untyped_atomic"; case SHADER_OPCODE_UNTYPED_SURFACE_READ: return "untyped_surface_read"; + case SHADER_OPCODE_BUFFER_LOAD: + return "buffer_load"; case SHADER_OPCODE_LOAD_PAYLOAD: return "load_payload"; diff --git a/src/mesa/drivers/dri/i965/brw_vec4_visitor.cpp b/src/mesa/drivers/dri/i965/brw_vec4_visitor.cpp index 195c6f5..887036e 100644 --- a/src/mesa/drivers/dri/i965/brw_vec4_visitor.cpp +++ b/src/mesa/drivers/dri/i965/brw_vec4_visitor.cpp @@ -788,7 +788,8 @@ vec4_visitor::emit_bool_to_cond_code(ir_rvalue *ir, *predicate = BRW_PREDICATE_NORMAL; - if (expr && expr->operation != ir_binop_ubo_load) { + if (expr && expr->operation != ir_binop_ubo_load && + expr->operation != ir_binop_ssbo_load) { src_reg op[3]; vec4_instruction *inst; @@ -936,7 +937,8 @@ vec4_visitor::emit_if_gen6(ir_if *ir) { ir_expression *expr = ir->condition->as_expression(); - if (expr && expr->operation != ir_binop_ubo_load) { + if (expr && expr->operation != ir_binop_ubo_load && + expr->operation != ir_binop_ssbo_load) { src_reg op[3]; dst_reg temp; @@ -1729,6 +1731,7 @@ vec4_visitor::visit(ir_expression *ir) emit(BFI1(result_dst, op[0], op[1])); break; + case ir_binop_ssbo_load: case ir_binop_ubo_load: { ir_constant *const_uniform_block = ir->operands[0]->as_constant(); ir_constant *const_offset_ir = ir->operands[1]->as_constant(); @@ -1821,6 +1824,10 @@ vec4_visitor::visit(ir_expression *ir) break; } + case ir_binop_ssbo_store: + assert(!"Not implemented"); + break; + case ir_binop_vector_extract: unreachable("should have been lowered by vec_index_to_cond_assign"); diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index c43c6ac..71c0592 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -2720,6 +2720,11 @@ struct gl_uniform_block GLuint UniformBufferSize; /** + * Is this actually an interface block for a shader storage buffer? + */ + bool IsBuffer; + + /** * Layout specified in the shader * * This isn't accessible through the API, but it is used while