panfrost: XMLify Midgard samplers
authorAlyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
Tue, 11 Aug 2020 22:23:12 +0000 (18:23 -0400)
committerTomeu Vizoso <tomeu.vizoso@collabora.com>
Thu, 13 Aug 2020 06:55:16 +0000 (08:55 +0200)
Signed-off-by: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
Reviewed-by: Tomeu Vizoso <tomeu.vizoso@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6195>

src/gallium/drivers/panfrost/pan_cmdstream.c
src/gallium/drivers/panfrost/pan_cmdstream.h
src/gallium/drivers/panfrost/pan_context.c
src/gallium/drivers/panfrost/pan_context.h
src/panfrost/include/panfrost-job.h
src/panfrost/lib/decode.c
src/panfrost/lib/midgard.xml
src/panfrost/lib/pan_blit.c

index cff19bf121dbabdc08668919a5cf6bba7f53e0f9..3d0a57aff24c0a560d8f70eb8e97c65ba0d051c1 100644 (file)
@@ -353,81 +353,83 @@ static unsigned
 translate_tex_wrap(enum pipe_tex_wrap w)
 {
         switch (w) {
-        case PIPE_TEX_WRAP_REPEAT:
-                return MALI_WRAP_MODE_REPEAT;
-
-        case PIPE_TEX_WRAP_CLAMP:
-                return MALI_WRAP_MODE_CLAMP;
-
-        case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
-                return MALI_WRAP_MODE_CLAMP_TO_EDGE;
-
-        case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
-                return MALI_WRAP_MODE_CLAMP_TO_BORDER;
-
-        case PIPE_TEX_WRAP_MIRROR_REPEAT:
-                return MALI_WRAP_MODE_MIRRORED_REPEAT;
+        case PIPE_TEX_WRAP_REPEAT: return MALI_WRAP_MODE_REPEAT;
+        case PIPE_TEX_WRAP_CLAMP: return MALI_WRAP_MODE_CLAMP;
+        case PIPE_TEX_WRAP_CLAMP_TO_EDGE: return MALI_WRAP_MODE_CLAMP_TO_EDGE;
+        case PIPE_TEX_WRAP_CLAMP_TO_BORDER: return MALI_WRAP_MODE_CLAMP_TO_BORDER;
+        case PIPE_TEX_WRAP_MIRROR_REPEAT: return MALI_WRAP_MODE_MIRRORED_REPEAT;
+        case PIPE_TEX_WRAP_MIRROR_CLAMP: return MALI_WRAP_MODE_MIRRORED_CLAMP;
+        case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: return MALI_WRAP_MODE_MIRRORED_CLAMP_TO_EDGE;
+        case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: return MALI_WRAP_MODE_MIRRORED_CLAMP_TO_BORDER;
+        default: unreachable("Invalid wrap");
+        }
+}
 
-        case PIPE_TEX_WRAP_MIRROR_CLAMP:
-                return MALI_WRAP_MODE_MIRRORED_CLAMP;
+/* The hardware compares in the wrong order order, so we have to flip before
+ * encoding. Yes, really. */
 
-        case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
-                return MALI_WRAP_MODE_MIRRORED_CLAMP_TO_EDGE;
+static enum mali_func
+panfrost_sampler_compare_func(const struct pipe_sampler_state *cso)
+{
+        if (!cso->compare_mode)
+                return MALI_FUNC_NEVER;
 
-        case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
-                return MALI_WRAP_MODE_MIRRORED_CLAMP_TO_BORDER;
+        enum mali_func f = panfrost_translate_compare_func(cso->compare_func);
+        return panfrost_flip_compare_func(f);
+}
 
-        default:
-                unreachable("Invalid wrap");
+static enum mali_mipmap_mode
+pan_pipe_to_mipmode(enum pipe_tex_mipfilter f)
+{
+        switch (f) {
+        case PIPE_TEX_MIPFILTER_NEAREST: return MALI_MIPMAP_MODE_NEAREST;
+        case PIPE_TEX_MIPFILTER_LINEAR: return MALI_MIPMAP_MODE_TRILINEAR;
+        case PIPE_TEX_MIPFILTER_NONE: return MALI_MIPMAP_MODE_NONE;
+        default: unreachable("Invalid");
         }
 }
 
 void panfrost_sampler_desc_init(const struct pipe_sampler_state *cso,
-                                struct mali_sampler_descriptor *hw)
+                                struct mali_midgard_sampler_packed *hw)
 {
-        unsigned func = panfrost_translate_compare_func(cso->compare_func);
-        bool min_nearest = cso->min_img_filter == PIPE_TEX_FILTER_NEAREST;
-        bool mag_nearest = cso->mag_img_filter == PIPE_TEX_FILTER_NEAREST;
-        bool mip_linear  = cso->min_mip_filter == PIPE_TEX_MIPFILTER_LINEAR;
-        unsigned min_filter = min_nearest ? MALI_SAMP_MIN_NEAREST : 0;
-        unsigned mag_filter = mag_nearest ? MALI_SAMP_MAG_NEAREST : 0;
-        unsigned mip_filter = mip_linear  ?
-                              (MALI_SAMP_MIP_LINEAR_1 | MALI_SAMP_MIP_LINEAR_2) : 0;
-        unsigned normalized = cso->normalized_coords ? MALI_SAMP_NORM_COORDS : 0;
-
-        *hw = (struct mali_sampler_descriptor) {
-                .filter_mode = min_filter | mag_filter | mip_filter |
-                               normalized,
-                .wrap_s = translate_tex_wrap(cso->wrap_s),
-                .wrap_t = translate_tex_wrap(cso->wrap_t),
-                .wrap_r = translate_tex_wrap(cso->wrap_r),
-                .compare_func = cso->compare_mode ?
-                        panfrost_flip_compare_func(func) :
-                        MALI_FUNC_NEVER,
-                .border_color = {
-                        cso->border_color.f[0],
-                        cso->border_color.f[1],
-                        cso->border_color.f[2],
-                        cso->border_color.f[3]
-                },
-                .min_lod = FIXED_16(cso->min_lod, false), /* clamp at 0 */
-                .max_lod = FIXED_16(cso->max_lod, false),
-                .lod_bias = FIXED_16(cso->lod_bias, true), /* can be negative */
-                .seamless_cube_map = cso->seamless_cube_map,
-        };
+        pan_pack(hw, MIDGARD_SAMPLER, cfg) {
+                cfg.magnify_nearest = cso->mag_img_filter == PIPE_TEX_FILTER_NEAREST;
+                cfg.minify_nearest = cso->min_img_filter == PIPE_TEX_FILTER_NEAREST;
+                cfg.mipmap_mode = (cso->min_mip_filter == PIPE_TEX_MIPFILTER_LINEAR) ?
+                        MALI_MIPMAP_MODE_TRILINEAR : MALI_MIPMAP_MODE_NEAREST;
+                cfg.normalized_coordinates = cso->normalized_coords;
 
-        /* If necessary, we disable mipmapping in the sampler descriptor by
-         * clamping the LOD as tight as possible (from 0 to epsilon,
-         * essentially -- remember these are fixed point numbers, so
-         * epsilon=1/256) */
+                cfg.lod_bias = FIXED_16(cso->lod_bias, true);
 
-        if (cso->min_mip_filter == PIPE_TEX_MIPFILTER_NONE)
-                hw->max_lod = hw->min_lod + 1;
+                cfg.minimum_lod = FIXED_16(cso->min_lod, false);
+
+                /* If necessary, we disable mipmapping in the sampler descriptor by
+                 * clamping the LOD as tight as possible (from 0 to epsilon,
+                 * essentially -- remember these are fixed point numbers, so
+                 * epsilon=1/256) */
+
+                cfg.maximum_lod = (cso->min_mip_filter == PIPE_TEX_MIPFILTER_NONE) ?
+                        cfg.minimum_lod + 1 :
+                        FIXED_16(cso->max_lod, false);
+
+                cfg.wrap_mode_s = translate_tex_wrap(cso->wrap_s);
+                cfg.wrap_mode_t = translate_tex_wrap(cso->wrap_t);
+                cfg.wrap_mode_r = translate_tex_wrap(cso->wrap_r);
+
+                cfg.compare_function = panfrost_sampler_compare_func(cso);
+                cfg.seamless_cube_map = cso->seamless_cube_map;
+
+                cfg.border_color_r = cso->border_color.f[0];
+                cfg.border_color_g = cso->border_color.f[0];
+                cfg.border_color_b = cso->border_color.f[0];
+                cfg.border_color_a = cso->border_color.f[0];
+        }
 }
 
 void panfrost_sampler_desc_init_bifrost(const struct pipe_sampler_state *cso,
-                                        struct bifrost_sampler_descriptor *hw)
+                                        uint32_t *_hw)
 {
+        struct bifrost_sampler_descriptor *hw = (struct bifrost_sampler_descriptor *) _hw;
         *hw = (struct bifrost_sampler_descriptor) {
                 .unk1 = 0x1,
                 .wrap_s = translate_tex_wrap(cso->wrap_s),
@@ -1326,34 +1328,21 @@ panfrost_emit_sampler_descriptors(struct panfrost_batch *batch,
                                   struct mali_vertex_tiler_postfix *postfix)
 {
         struct panfrost_context *ctx = batch->ctx;
-        struct panfrost_device *device = pan_device(ctx->base.screen);
 
         if (!ctx->sampler_count[stage])
                 return;
 
-        if (device->quirks & IS_BIFROST) {
-                size_t desc_size = sizeof(struct bifrost_sampler_descriptor);
-                size_t transfer_size = desc_size * ctx->sampler_count[stage];
-                struct panfrost_transfer transfer = panfrost_pool_alloc(&batch->pool,
-                                                                                transfer_size);
-                struct bifrost_sampler_descriptor *desc = (struct bifrost_sampler_descriptor *)transfer.cpu;
-
-                for (int i = 0; i < ctx->sampler_count[stage]; ++i)
-                        desc[i] = ctx->samplers[stage][i]->bifrost_hw;
+        size_t desc_size = sizeof(struct bifrost_sampler_descriptor);
+        assert(sizeof(struct bifrost_sampler_descriptor) == MALI_MIDGARD_SAMPLER_LENGTH);
 
-                postfix->sampler_descriptor = transfer.gpu;
-        } else {
-                size_t desc_size = sizeof(struct mali_sampler_descriptor);
-                size_t transfer_size = desc_size * ctx->sampler_count[stage];
-                struct panfrost_transfer transfer = panfrost_pool_alloc(&batch->pool,
-                                                                                transfer_size);
-                struct mali_sampler_descriptor *desc = (struct mali_sampler_descriptor *)transfer.cpu;
+        size_t sz = desc_size * ctx->sampler_count[stage];
+        struct panfrost_transfer T = panfrost_pool_alloc(&batch->pool, sz);
+        struct mali_midgard_sampler_packed *out = (struct mali_midgard_sampler_packed *) T.cpu;
 
-                for (int i = 0; i < ctx->sampler_count[stage]; ++i)
-                        desc[i] = ctx->samplers[stage][i]->midgard_hw;
+        for (unsigned i = 0; i < ctx->sampler_count[stage]; ++i)
+                out[i] = ctx->samplers[stage][i]->hw;
 
-                postfix->sampler_descriptor = transfer.gpu;
-        }
+        postfix->sampler_descriptor = T.gpu;
 }
 
 void
index 7847338e6a6b1fa19cc89d2e27458798eb5e4c79..089f192cb84bee80aa3342fd086fba4aa90f79ea 100644 (file)
 
 #include "pan_job.h"
 
-void panfrost_sampler_desc_init(const struct pipe_sampler_state *cso,
-                                struct mali_sampler_descriptor *hw);
-
-void panfrost_sampler_desc_init_bifrost(const struct pipe_sampler_state *cso,
-                                        struct bifrost_sampler_descriptor *hw);
+void panfrost_sampler_desc_init(const struct pipe_sampler_state *cso, struct mali_midgard_sampler_packed *hw);
+void panfrost_sampler_desc_init_bifrost(const struct pipe_sampler_state *cso, uint32_t *hw);
 
 void
 panfrost_vt_init(struct panfrost_context *ctx,
index 400d83da8095fb82f1b3551446b112120a0dd254..6b9166094860d449c3c4f3ea8e1e280a7174af87 100644 (file)
@@ -605,9 +605,9 @@ panfrost_create_sampler_state(
         so->base = *cso;
 
         if (device->quirks & IS_BIFROST)
-                panfrost_sampler_desc_init_bifrost(cso, &so->bifrost_hw);
+                panfrost_sampler_desc_init_bifrost(cso, (uint32_t *) &so->hw);
         else
-                panfrost_sampler_desc_init(cso, &so->midgard_hw);
+                panfrost_sampler_desc_init(cso, &so->hw);
 
         return so;
 }
index 5e0bce31e1d5137c7d79ad7d9d5b41a8cd36de7d..680ff5e64e75eef162f24fa1e5705e8c06678d36 100644 (file)
@@ -269,8 +269,7 @@ struct panfrost_zsa_state {
 
 struct panfrost_sampler_state {
         struct pipe_sampler_state base;
-        struct mali_sampler_descriptor midgard_hw;
-        struct bifrost_sampler_descriptor bifrost_hw;
+        struct mali_midgard_sampler_packed hw;
 };
 
 /* Misnomer: Sampler view corresponds to textures, not samplers */
index 7f8e85e0f0a14035bf3441cd202d25b8363e8b98..534e546254527d28ee42a8d2ee06acfe54a3b5cb 100644 (file)
@@ -1254,21 +1254,6 @@ struct bifrost_texture_descriptor {
         uint16_t unk5;
 } __attribute__((packed));
 
-/* filter_mode */
-
-#define MALI_SAMP_MAG_NEAREST (1 << 0)
-#define MALI_SAMP_MIN_NEAREST (1 << 1)
-
-/* TODO: What do these bits mean individually? Only seen set together */
-
-#define MALI_SAMP_MIP_LINEAR_1 (1 << 3)
-#define MALI_SAMP_MIP_LINEAR_2 (1 << 4)
-
-/* Flag in filter_mode, corresponding to OpenCL's NORMALIZED_COORDS_TRUE
- * sampler_t flag. For typical OpenGL textures, this is always set. */
-
-#define MALI_SAMP_NORM_COORDS (1 << 5)
-
 /* Used for lod encoding. Thanks @urjaman for pointing out these routines can
  * be cleaned up a lot. */
 
@@ -1286,35 +1271,6 @@ FIXED_16(float x, bool allow_negative)
         return (int) (x * 256.0);
 }
 
-struct mali_sampler_descriptor {
-        uint16_t filter_mode;
-
-        /* Fixed point, signed.
-         * Upper 7 bits before the decimal point, although it caps [0-31].
-         * Lower 8 bits after the decimal point: int(round(x * 256)) */
-
-        int16_t lod_bias;
-        int16_t min_lod;
-        int16_t max_lod;
-
-        /* All one word in reality, but packed a bit. Comparisons are flipped
-         * from OpenGL. */
-
-        enum mali_wrap_mode wrap_s : 4;
-        enum mali_wrap_mode wrap_t : 4;
-        enum mali_wrap_mode wrap_r : 4;
-        enum mali_func compare_func : 3;
-
-        /* No effect on 2D textures. For cubemaps, set for ES3 and clear for
-         * ES2, controlling seamless cubemapping */
-        unsigned seamless_cube_map : 1;
-
-        unsigned zero : 16;
-
-        uint32_t zero2;
-        float border_color[4];
-} __attribute__((packed));
-
 /* Bifrost sampler descriptors look pretty similar */
 
 #define BIFROST_SAMP_MIN_NEAREST        (1)
index 487d23c3caef505efcdaff4741e375ed7539378d..b39aba081451c0656c2904fa39a7a0e304429ff9 100644 (file)
@@ -61,7 +61,7 @@ static void pandecode_swizzle(unsigned swizzle, enum mali_format format);
         fprintf(pandecode_dump_stream, "%s\n", title); \
         struct MALI_ ## T temp; \
         MALI_ ## T ## _unpack((const uint8_t *) cl, &temp); \
-        MALI_ ## T ## _print(pandecode_dump_stream, &temp, 0); \
+        MALI_ ## T ## _print(pandecode_dump_stream, &temp, indent * 2); \
 }
 
 #define DUMP_ADDR(title, T, addr, indent) {\
@@ -318,17 +318,6 @@ static const struct pandecode_flag_info mfbd_flag_info [] = {
 };
 #undef FLAG_INFO
 
-#define FLAG_INFO(flag) { MALI_SAMP_##flag, "MALI_SAMP_" #flag }
-static const struct pandecode_flag_info sampler_flag_info [] = {
-        FLAG_INFO(MAG_NEAREST),
-        FLAG_INFO(MIN_NEAREST),
-        FLAG_INFO(MIP_LINEAR_1),
-        FLAG_INFO(MIP_LINEAR_2),
-        FLAG_INFO(NORM_COORDS),
-        {}
-};
-#undef FLAG_INFO
-
 #define FLAG_INFO(flag) { MALI_SFBD_FORMAT_##flag, "MALI_SFBD_FORMAT_" #flag }
 static const struct pandecode_flag_info sfbd_unk1_info [] = {
         FLAG_INFO(MSAA_8),
@@ -2481,46 +2470,8 @@ pandecode_samplers(mali_ptr samplers, unsigned sampler_count, int job_no, bool i
                         pandecode_log("};\n");
                 }
         } else {
-                struct mali_sampler_descriptor *s;
-
-                for (int i = 0; i < sampler_count; ++i) {
-                        s = pandecode_fetch_gpu_mem(smem, samplers + sizeof(*s) * i, sizeof(*s));
-
-                        pandecode_log("struct mali_sampler_descriptor sampler_descriptor_%"PRIx64"_%d_%d = {\n", samplers + sizeof(*s) * i, job_no, i);
-                        pandecode_indent++;
-
-                        pandecode_log(".filter_mode = ");
-                        pandecode_log_decoded_flags(sampler_flag_info, s->filter_mode);
-                        pandecode_log_cont(",\n");
-
-                        pandecode_prop("min_lod = FIXED_16(%f)", DECODE_FIXED_16(s->min_lod));
-                        pandecode_prop("max_lod = FIXED_16(%f)", DECODE_FIXED_16(s->max_lod));
-
-                        if (s->lod_bias)
-                                pandecode_prop("lod_bias = FIXED_16(%f)", DECODE_FIXED_16(s->lod_bias));
-
-                        pandecode_prop("wrap_s = %s", mali_wrap_mode_as_str(s->wrap_s));
-                        pandecode_prop("wrap_t = %s", mali_wrap_mode_as_str(s->wrap_t));
-                        pandecode_prop("wrap_r = %s", mali_wrap_mode_as_str(s->wrap_r));
-
-                        pandecode_prop("compare_func = %s", mali_func_as_str(s->compare_func));
-
-                        if (s->zero || s->zero2) {
-                                pandecode_msg("XXX: sampler zero tripped\n");
-                                pandecode_prop("zero = 0x%X, 0x%X\n", s->zero, s->zero2);
-                        }
-
-                        pandecode_prop("seamless_cube_map = %d", s->seamless_cube_map);
-
-                        pandecode_prop("border_color = { %f, %f, %f, %f }",
-                                       s->border_color[0],
-                                       s->border_color[1],
-                                       s->border_color[2],
-                                       s->border_color[3]);
-
-                        pandecode_indent--;
-                        pandecode_log("};\n");
-                }
+                for (int i = 0; i < sampler_count; ++i)
+                        DUMP_ADDR("Sampler", MIDGARD_SAMPLER, samplers + (MALI_MIDGARD_SAMPLER_LENGTH * i), 1);
         }
 }
 
index d3a40da45bdadb797661b964cc56b4d13da7132f..09191accec5ffc2be2c288f3342033ca6e389d23 100644 (file)
     <value name="Always" value="7"/>
   </enum>
 
+  <enum name="Mipmap Mode">
+    <value name="Nearest" value="0"/>
+    <value name="None" value="1"/>
+    <value name="Trilinear" value="3"/>
+  </enum>
+
   <enum name="Stencil Op">
     <value name="Keep" value="0"/>
     <value name="Replace" value="1"/>
     <value name="Mirrored Clamp to Border" value="15"/>
   </enum>
 
+  <struct name="Midgard Sampler">
+    <field name="Magnify Nearest" size="1" start="0" type="bool" default="true"/>
+    <field name="Minify Nearest" size="1" start="1" type="bool" default="true"/>
+    <field name="Mipmap Mode" size="2" start="3" type="Mipmap Mode" default="Nearest"/>
+    <field name="Normalized Coordinates" size="1" start="5" type="bool" default="true"/>
+    <field name="LOD Bias" size="16" start="0:16" type="int" default="0"/>
+    <field name="Minimum LOD" size="16" start="1:0" type="uint" default="0"/>
+    <field name="Maximum LOD" size="16" start="1:16" type="uint" default="1"/>
+    <field name="Wrap Mode S" size="4" start="2:0" type="Wrap Mode" default="Clamp to Edge"/>
+    <field name="Wrap Mode T" size="4" start="2:4" type="Wrap Mode" default="Clamp to Edge"/>
+    <field name="Wrap Mode R" size="4" start="2:8" type="Wrap Mode" default="Clamp to Edge"/>
+    <field name="Compare Function" size="3" start="2:12" type="Func" default="Never"/>
+    <field name="Seamless Cube Map" size="1" start="2:15" type="bool" default="true"/>
+    <field name="Border Color R" size="32" start="4:0" type="float" default="0.0"/>
+    <field name="Border Color G" size="32" start="5:0" type="float" default="0.0"/>
+    <field name="Border Color B" size="32" start="6:0" type="float" default="0.0"/>
+    <field name="Border Color A" size="32" start="7:0" type="float" default="0.0"/>
+  </struct>
+
   <struct name="Stencil">
     <field name="Reference Value" size="8" start="0" type="uint"/>
     <field name="Mask" size="8" start="8" type="uint" default="0xFF"/>
index 69b4b41791287e7186a42b4deb88ed9c8ee5884b..28e0b8aeb4f04add3ebfdcb38bc13ebc11ecaf2f 100644 (file)
@@ -187,6 +187,7 @@ panfrost_load_midg(
         unsigned height = u_minify(image->height0, image->first_level);
 
         struct panfrost_transfer viewport = panfrost_pool_alloc(pool, MALI_VIEWPORT_LENGTH);
+        struct panfrost_transfer sampler = panfrost_pool_alloc(pool, MALI_MIDGARD_SAMPLER_LENGTH);
 
         pan_pack(viewport.cpu, VIEWPORT, cfg) {
                 cfg.scissor_maximum_x = width - 1; /* Inclusive */
@@ -306,12 +307,8 @@ panfrost_load_midg(
                                         image->cubemap_stride, image->first_level),
                         image->slices);
 
-        struct mali_sampler_descriptor sampler = {
-                .filter_mode = MALI_SAMP_MAG_NEAREST | MALI_SAMP_MIN_NEAREST,
-                .wrap_s = MALI_WRAP_MODE_CLAMP_TO_EDGE,
-                .wrap_t = MALI_WRAP_MODE_CLAMP_TO_EDGE,
-                .wrap_r = MALI_WRAP_MODE_CLAMP_TO_EDGE,
-        };
+        pan_pack(sampler.cpu, MIDGARD_SAMPLER, cfg)
+                cfg.normalized_coordinates = false;
 
         struct panfrost_transfer shader_meta_t = panfrost_pool_alloc(pool, sizeof(shader_meta) + 8 * sizeof(struct midgard_blend_rt));
         memcpy(shader_meta_t.cpu, &shader_meta, sizeof(shader_meta));
@@ -349,7 +346,7 @@ panfrost_load_midg(
                         .gl_enables = 0x7,
                         .position_varying = coordinates,
                         .textures = panfrost_pool_upload(pool, &texture_t.gpu, sizeof(texture_t.gpu)),
-                        .sampler_descriptor = panfrost_pool_upload(pool, &sampler, sizeof(sampler)),
+                        .sampler_descriptor = sampler.gpu,
                         .shader = shader_meta_t.gpu,
                         .varyings = panfrost_pool_upload(pool, &varying, sizeof(varying)),
                         .varying_meta = panfrost_pool_upload(pool, &varying_meta, sizeof(varying_meta)),