Because of the combinatorial explosion of different image built-ins with different image dimensionalities and base data types, enumerating all the 242 possibilities would be annoying and a waste of .text space. Instead use a special path in the built-in builder that loops over all the known image types. --- src/glsl/builtin_functions.cpp | 378 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 378 insertions(+)
diff --git a/src/glsl/builtin_functions.cpp b/src/glsl/builtin_functions.cpp index a1a338d..760e264 100644 --- a/src/glsl/builtin_functions.cpp +++ b/src/glsl/builtin_functions.cpp @@ -334,12 +334,20 @@ shader_atomic_counters(const _mesa_glsl_parse_state *state) return state->ARB_shader_atomic_counters_enable; } +static bool +shader_image_load_store(const _mesa_glsl_parse_state *state) +{ + return state->ARB_shader_image_load_store_enable; +} + /** @} */ /******************************************************************************/ namespace { +class image_builtin_builder; + /** * builtin_builder: A singleton object representing the core of the built-in * function module. @@ -406,6 +414,13 @@ private: /** Create a new function and add the given signatures. */ void add_function(const char *name, ...); + /** + * Create a new function calling \param func for each known image + * type to generate its signatures. + */ + void add_image_function(const char *name, + const image_builtin_builder &func); + ir_function_signature *new_sig(const glsl_type *return_type, builtin_available_predicate avail, int num_params, ...); @@ -569,6 +584,11 @@ private: ir_function_signature *_atomic_op(const char *intrinsic, builtin_available_predicate avail); + ir_function_signature *_memory_barrier_intrinsic( + builtin_available_predicate avail); + ir_function_signature *_memory_barrier( + builtin_available_predicate avail); + #undef B0 #undef B1 #undef B2 @@ -576,6 +596,171 @@ private: #undef BA1 #undef BA2 /** @} */ + + friend class image_builtin_builder; +}; + +/** + * Functor that generates image load, store or atomic built-in + * signatures given some settings. + */ +class image_builtin_builder +{ +public: + image_builtin_builder(builtin_builder &bld) + : bld(bld), + _emit_stub(false), + _intrinsic_name(NULL), + _has_return(false), + _has_arguments(0), + _has_vector_data_type(false), + _has_float_data_type(false), + _read_only(false), + _write_only(false) + { + } + + /** + * Build a stub function that calls \c intrinsic_name forwarding + * arguments and return type. + */ + image_builtin_builder & + emit_stub(const char *intrinsic_name) + { + _emit_stub = true; + _intrinsic_name = intrinsic_name; + return *this; + } + + image_builtin_builder & + has_return() + { + _has_return = true; + return *this; + } + + image_builtin_builder & + has_arguments(unsigned n) + { + _has_arguments = n; + return *this; + } + + image_builtin_builder & + has_vector_data_type() + { + _has_vector_data_type = true; + return *this; + } + + image_builtin_builder & + has_float_data_type() + { + _has_float_data_type = true; + return *this; + } + + image_builtin_builder & + read_only() + { + _read_only = true; + return *this; + } + + image_builtin_builder & + write_only() + { + _write_only = true; + return *this; + } + + /** + * Generate the image built-in. + */ + ir_function_signature * + operator()(const glsl_type *image_type) const + { + if (image_type->fields.image.type == GLSL_TYPE_FLOAT && + !_has_float_data_type) + return NULL; + + ir_function_signature *sig = create_signature(image_type); + + if (_emit_stub) { + ir_factory body(&sig->body, bld.mem_ctx); + ir_function *f = bld.shader->symbols->get_function(_intrinsic_name); + + if (_has_return) { + ir_variable *ret_val = + body.make_temp(sig->return_type, "_ret_val"); + body.emit(bld.call(f, ret_val, sig->parameters)); + body.emit(ret(ret_val)); + } else { + body.emit(bld.call(f, NULL, sig->parameters)); + } + + sig->is_defined = true; + + } else { + sig->is_intrinsic = true; + } + + return sig; + } + +private: + ir_function_signature * + create_signature(const glsl_type *image_type) const + { + const glsl_type *data_type = + glsl_type::get_instance(image_type->fields.image.type, + (_has_vector_data_type ? 4 : 1), 1); + const glsl_type *ret_type = (_has_return ? data_type : + glsl_type::void_type); + + /* Addressing arguments that are always present. */ + ir_variable *image = bld.in_var(image_type, "image"); + ir_variable *coord = bld.in_var( + glsl_type::ivec(image_type->coordinate_components()), "coord"); + + ir_function_signature *sig = + bld.new_sig(ret_type, shader_image_load_store, 2, image, coord); + + /* Sample index for multisample images. */ + if (image_type->fields.image.dimension == GLSL_IMAGE_DIM_MS) + sig->parameters.push_tail( + bld.in_var(glsl_type::int_type, "sample")); + + /* Data arguments. */ + for (unsigned i = 0; i < _has_arguments; ++i) + sig->parameters.push_tail( + bld.in_var(data_type, ralloc_asprintf(NULL, "arg%d", i))); + + /* Set the maximal set of qualifiers allowed for this image + * built-in. Function calls with arguments having fewer + * qualifiers than present in the prototype are allowed by the + * spec, but not with more, i.e. this will make the compiler + * accept everything that needs to be accepted, and reject cases + * like loads from write-only or stores to read-only images. + */ + image->image.read_only = _read_only; + image->image.write_only = _write_only; + image->image.coherent = true; + image->image._volatile = true; + image->image._restrict = true; + + return sig; + } + + builtin_builder &bld; + bool _emit_stub; + const char *_intrinsic_name; + bool _has_return; + unsigned _has_arguments; + bool _has_vector_data_type; + bool _has_float_data_type; + bool _read_only; + bool _write_only; }; } /* anonymous namespace */ @@ -684,6 +869,64 @@ builtin_builder::create_intrinsics() add_function("__intrinsic_atomic_predecrement", _atomic_intrinsic(shader_atomic_counters), NULL); + + add_image_function("__intrinsic_image_load", + image_builtin_builder(*this) + .has_return() + .has_vector_data_type() + .has_float_data_type() + .read_only()); + + add_image_function("__intrinsic_image_store", + image_builtin_builder(*this) + .has_arguments(1) + .has_vector_data_type() + .has_float_data_type() + .write_only()); + + add_image_function("__intrinsic_image_atomic_add", + image_builtin_builder(*this) + .has_return() + .has_arguments(1)); + + add_image_function("__intrinsic_image_atomic_min", + image_builtin_builder(*this) + .has_return() + .has_arguments(1)); + + add_image_function("__intrinsic_image_atomic_max", + image_builtin_builder(*this) + .has_return() + .has_arguments(1)); + + add_image_function("__intrinsic_image_atomic_and", + image_builtin_builder(*this) + .has_return() + .has_arguments(1)); + + add_image_function("__intrinsic_image_atomic_or", + image_builtin_builder(*this) + .has_return() + .has_arguments(1)); + + add_image_function("__intrinsic_image_atomic_xor", + image_builtin_builder(*this) + .has_return() + .has_arguments(1)); + + add_image_function("__intrinsic_image_atomic_exchange", + image_builtin_builder(*this) + .has_return() + .has_arguments(1)); + + add_image_function("__intrinsic_image_atomic_comp_swap", + image_builtin_builder(*this) + .has_return() + .has_arguments(2)); + + add_function("__intrinsic_memory_barrier", + _memory_barrier_intrinsic(shader_image_load_store), + NULL); } /** @@ -2106,6 +2349,74 @@ builtin_builder::create_builtins() shader_atomic_counters), NULL); + add_image_function("imageLoad", + image_builtin_builder(*this) + .emit_stub("__intrinsic_image_load") + .has_return() + .has_vector_data_type() + .has_float_data_type() + .read_only()); + + add_image_function("imageStore", + image_builtin_builder(*this) + .emit_stub("__intrinsic_image_store") + .has_arguments(1) + .has_vector_data_type() + .has_float_data_type() + .write_only()); + + add_image_function("imageAtomicAdd", + image_builtin_builder(*this) + .emit_stub("__intrinsic_image_atomic_add") + .has_return() + .has_arguments(1)); + + add_image_function("imageAtomicMin", + image_builtin_builder(*this) + .emit_stub("__intrinsic_image_atomic_min") + .has_return() + .has_arguments(1)); + + add_image_function("imageAtomicMax", + image_builtin_builder(*this) + .emit_stub("__intrinsic_image_atomic_max") + .has_return() + .has_arguments(1)); + + add_image_function("imageAtomicAnd", + image_builtin_builder(*this) + .emit_stub("__intrinsic_image_atomic_and") + .has_return() + .has_arguments(1)); + + add_image_function("imageAtomicOr", + image_builtin_builder(*this) + .emit_stub("__intrinsic_image_atomic_or") + .has_return() + .has_arguments(1)); + + add_image_function("imageAtomicXor", + image_builtin_builder(*this) + .emit_stub("__intrinsic_image_atomic_xor") + .has_return() + .has_arguments(1)); + + add_image_function("imageAtomicExchange", + image_builtin_builder(*this) + .emit_stub("__intrinsic_image_atomic_exchange") + .has_return() + .has_arguments(1)); + + add_image_function("imageAtomicCompSwap", + image_builtin_builder(*this) + .emit_stub("__intrinsic_image_atomic_comp_swap") + .has_return() + .has_arguments(2)); + + add_function("memoryBarrier", + _memory_barrier(shader_image_load_store), + NULL); + #undef F #undef FI #undef FIU @@ -2139,6 +2450,57 @@ builtin_builder::add_function(const char *name, ...) shader->symbols->add_function(f); } +void +builtin_builder::add_image_function(const char *name, + const image_builtin_builder &proc) +{ + static const glsl_type *const types[] = { + glsl_type::image1D_type, + glsl_type::image2D_type, + glsl_type::image3D_type, + glsl_type::image2DRect_type, + glsl_type::imageCube_type, + glsl_type::imageBuffer_type, + glsl_type::image1DArray_type, + glsl_type::image2DArray_type, + glsl_type::imageCubeArray_type, + glsl_type::image2DMS_type, + glsl_type::image2DMSArray_type, + glsl_type::iimage1D_type, + glsl_type::iimage2D_type, + glsl_type::iimage3D_type, + glsl_type::iimage2DRect_type, + glsl_type::iimageCube_type, + glsl_type::iimageBuffer_type, + glsl_type::iimage1DArray_type, + glsl_type::iimage2DArray_type, + glsl_type::iimageCubeArray_type, + glsl_type::iimage2DMS_type, + glsl_type::iimage2DMSArray_type, + glsl_type::uimage1D_type, + glsl_type::uimage2D_type, + glsl_type::uimage3D_type, + glsl_type::uimage2DRect_type, + glsl_type::uimageCube_type, + glsl_type::uimageBuffer_type, + glsl_type::uimage1DArray_type, + glsl_type::uimage2DArray_type, + glsl_type::uimageCubeArray_type, + glsl_type::uimage2DMS_type, + glsl_type::uimage2DMSArray_type + }; + ir_function *f = new(mem_ctx) ir_function(name); + + for (unsigned i = 0; i < Elements(types); ++i) { + ir_function_signature *sig = proc(types[i]); + + if (sig) + f->add_signature(sig); + } + + shader->symbols->add_function(f); +} + ir_variable * builtin_builder::in_var(const glsl_type *type, const char *name) { @@ -3991,6 +4353,22 @@ builtin_builder::_atomic_op(const char *intrinsic, return sig; } +ir_function_signature * +builtin_builder::_memory_barrier_intrinsic(builtin_available_predicate avail) +{ + MAKE_INTRINSIC(glsl_type::void_type, avail, 0); + return sig; +} + +ir_function_signature * +builtin_builder::_memory_barrier(builtin_available_predicate avail) +{ + MAKE_SIG(glsl_type::void_type, avail, 0); + body.emit(call(shader->symbols->get_function("__intrinsic_memory_barrier"), + NULL, sig->parameters)); + return sig; +} + /** @} */ /******************************************************************************/ -- 1.8.3.4 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev