r600g: add back u_upload_mgr integration
authorMarek Olšák <maraeo@gmail.com>
Fri, 28 Jan 2011 02:03:38 +0000 (03:03 +0100)
committerMarek Olšák <maraeo@gmail.com>
Sun, 30 Jan 2011 02:29:48 +0000 (03:29 +0100)
I can't see a performance difference with this code, which means all
the driver-specific code removed in this commit was unnecessary.

Now we use u_upload_mgr in a slightly different way than we did before it got
dropped. I am not restoring the original code "as is" due to latest
u_upload_mgr changes that r300g performance benefits from.

This also fixes:
- piglit/fp-kil

src/gallium/drivers/r600/Makefile
src/gallium/drivers/r600/SConscript
src/gallium/drivers/r600/evergreen_state.c
src/gallium/drivers/r600/r600_buffer.c
src/gallium/drivers/r600/r600_pipe.c
src/gallium/drivers/r600/r600_pipe.h
src/gallium/drivers/r600/r600_resource.h
src/gallium/drivers/r600/r600_state.c
src/gallium/drivers/r600/r600_state_common.c
src/gallium/drivers/r600/r600_upload.c [deleted file]

index b476b9af3b834e717a88dea66a2395202715d0e3..a484f38e9f12fcbf795e35cf8332d612bb699e4d 100644 (file)
@@ -21,7 +21,6 @@ C_SOURCES = \
        evergreen_state.c \
        eg_asm.c \
        r600_translate.c \
-       r600_state_common.c \
-       r600_upload.c
+       r600_state_common.c
 
 include ../../Makefile.template
index e51f50c5df5ed77de4efbe45c916c9c8c7f7f5ba..5a5fa6d65fdd19c8eb1d6e8fca5c187542796fb3 100644 (file)
@@ -28,7 +28,6 @@ r600 = env.ConvenienceLibrary(
         'r600_state_common.c',
         'r600_texture.c',
         'r600_translate.c',
-        'r600_upload.c',
         'r700_asm.c',
         'evergreen_state.c',
         'eg_asm.c',
index 306ca03234f0bd252182bff49ff1985f68679cb9..2c9dd4799795a45318d3400dd525433e05da46d8 100644 (file)
@@ -841,7 +841,7 @@ static void evergreen_set_constant_buffer(struct pipe_context *ctx, uint shader,
                                        struct pipe_resource *buffer)
 {
        struct r600_pipe_context *rctx = (struct r600_pipe_context *)ctx;
-       struct r600_resource *rbuffer = (struct r600_resource*)buffer;
+       struct r600_resource_buffer *rbuffer = r600_buffer(buffer);
        uint32_t offset;
 
        /* Note that the state tracker can unbind constant buffers by
@@ -851,7 +851,7 @@ static void evergreen_set_constant_buffer(struct pipe_context *ctx, uint shader,
                return;
        }
 
-       r600_upload_const_buffer(rctx, buffer, &offset);
+       r600_upload_const_buffer(rctx, &rbuffer, &offset);
 
        switch (shader) {
        case PIPE_SHADER_VERTEX:
@@ -862,7 +862,7 @@ static void evergreen_set_constant_buffer(struct pipe_context *ctx, uint shader,
                                        0xFFFFFFFF, NULL);
                r600_pipe_state_add_reg(&rctx->vs_const_buffer,
                                        R_028980_ALU_CONST_CACHE_VS_0,
-                                       (r600_bo_offset(rbuffer->bo) + offset) >> 8, 0xFFFFFFFF, rbuffer->bo);
+                                       (r600_bo_offset(rbuffer->r.bo) + offset) >> 8, 0xFFFFFFFF, rbuffer->r.bo);
                r600_context_pipe_state_set(&rctx->ctx, &rctx->vs_const_buffer);
                break;
        case PIPE_SHADER_FRAGMENT:
@@ -873,13 +873,16 @@ static void evergreen_set_constant_buffer(struct pipe_context *ctx, uint shader,
                                        0xFFFFFFFF, NULL);
                r600_pipe_state_add_reg(&rctx->ps_const_buffer,
                                        R_028940_ALU_CONST_CACHE_PS_0,
-                                       (r600_bo_offset(rbuffer->bo) + offset) >> 8, 0xFFFFFFFF, rbuffer->bo);
+                                       (r600_bo_offset(rbuffer->r.bo) + offset) >> 8, 0xFFFFFFFF, rbuffer->r.bo);
                r600_context_pipe_state_set(&rctx->ctx, &rctx->ps_const_buffer);
                break;
        default:
                R600_ERR("unsupported %d\n", shader);
                return;
        }
+
+       if (!rbuffer->user_buffer)
+               pipe_resource_reference((struct pipe_resource**)&rbuffer, NULL);
 }
 
 void evergreen_init_state_functions(struct r600_pipe_context *rctx)
index 469c8195fe9b7a8739fa1512dabd8239366b599e..f22475460623c6fe6076cd4e2ece6495c031b338 100644 (file)
 #include <util/u_math.h>
 #include <util/u_inlines.h>
 #include <util/u_memory.h>
+#include "util/u_upload_mgr.h"
+
 #include "state_tracker/drm_driver.h"
+
 #include <xf86drm.h>
 #include "radeon_drm.h"
+
 #include "r600.h"
 #include "r600_pipe.h"
 
 extern struct u_resource_vtbl r600_buffer_vtbl;
 
-
 struct pipe_resource *r600_buffer_create(struct pipe_screen *screen,
                                         const struct pipe_resource *templ)
 {
@@ -58,7 +61,6 @@ struct pipe_resource *r600_buffer_create(struct pipe_screen *screen,
        rbuffer->r.base.vtbl = &r600_buffer_vtbl;
        rbuffer->r.size = rbuffer->r.base.b.width0;
        rbuffer->r.bo_size = rbuffer->r.size;
-       rbuffer->uploaded = FALSE;
        bo = r600_bo((struct radeon*)screen->winsys, rbuffer->r.base.b.width0, alignment, rbuffer->r.base.b.bind, rbuffer->r.base.b.usage);
        if (bo == NULL) {
                FREE(rbuffer);
@@ -94,7 +96,6 @@ struct pipe_resource *r600_user_buffer_create(struct pipe_screen *screen,
        rbuffer->r.bo = NULL;
        rbuffer->r.bo_size = 0;
        rbuffer->user_buffer = ptr;
-       rbuffer->uploaded = FALSE;
        return &rbuffer->r.base.b;
 }
 
@@ -198,32 +199,23 @@ struct u_resource_vtbl r600_buffer_vtbl =
        u_default_transfer_inline_write         /* transfer_inline_write */
 };
 
-int r600_upload_index_buffer(struct r600_pipe_context *rctx, struct r600_drawl *draw)
+void r600_upload_index_buffer(struct r600_pipe_context *rctx, struct r600_drawl *draw)
 {
-       if (r600_buffer_is_user_buffer(draw->index_buffer)) {
+
+       if (r600_is_user_buffer(draw->index_buffer)) {
                struct r600_resource_buffer *rbuffer = r600_buffer(draw->index_buffer);
-               unsigned upload_offset;
-               int ret = 0;
-
-               ret = r600_upload_buffer(rctx->rupload_vb,
-                                       draw->index_buffer_offset,
-                                       draw->count * draw->index_size,
-                                       rbuffer,
-                                       &upload_offset,
-                                       &rbuffer->r.bo_size,
-                                       &rbuffer->r.bo);
-               if (ret)
-                       return ret;
-               rbuffer->uploaded = TRUE;
-               draw->index_buffer_offset = upload_offset;
-       }
+               boolean flushed;
 
-       return 0;
+               u_upload_data(rctx->upload_vb, 0,
+                             draw->count * draw->index_size,
+                             rbuffer->user_buffer,
+                             &draw->index_buffer_offset,
+                             &draw->index_buffer, &flushed);
+       }
 }
 
-int r600_upload_user_buffers(struct r600_pipe_context *rctx)
+void r600_upload_user_buffers(struct r600_pipe_context *rctx)
 {
-       enum pipe_error ret = PIPE_OK;
        int i, nr;
 
        nr = rctx->vertex_elements->count;
@@ -232,47 +224,33 @@ int r600_upload_user_buffers(struct r600_pipe_context *rctx)
        for (i = 0; i < nr; i++) {
                struct pipe_vertex_buffer *vb = &rctx->vertex_buffer[i];
 
-               if (r600_buffer_is_user_buffer(vb->buffer)) {
+               if (r600_is_user_buffer(vb->buffer)) {
                        struct r600_resource_buffer *rbuffer = r600_buffer(vb->buffer);
-                       unsigned upload_offset;
-
-                       ret = r600_upload_buffer(rctx->rupload_vb,
-                                               0, vb->buffer->width0,
-                                               rbuffer,
-                                               &upload_offset,
-                                               &rbuffer->r.bo_size,
-                                               &rbuffer->r.bo);
-                       if (ret)
-                               return ret;
-                       rbuffer->uploaded = TRUE;
-                       vb->buffer_offset = upload_offset;
+                       boolean flushed;
+
+                       u_upload_data(rctx->upload_vb, 0,
+                                     vb->buffer->width0,
+                                     rbuffer->user_buffer,
+                                     &vb->buffer_offset,
+                                     &vb->buffer,
+                                     &flushed);
                }
        }
-       return ret;
 }
 
-
-int r600_upload_const_buffer(struct r600_pipe_context *rctx, struct pipe_resource *cbuffer,
+void r600_upload_const_buffer(struct r600_pipe_context *rctx, struct r600_resource_buffer **rbuffer,
                             uint32_t *const_offset)
 {
-       if (r600_buffer_is_user_buffer(cbuffer)) {
-               struct r600_resource_buffer *rbuffer = r600_buffer(cbuffer);
-               unsigned upload_offset;
-               int ret = 0;
-
-               ret = r600_upload_buffer(rctx->rupload_const,
-                                        0, cbuffer->width0,
-                                        rbuffer,
-                                        &upload_offset,
-                                        &rbuffer->r.bo_size,
-                                        &rbuffer->r.bo);
-               if (ret)
-                       return ret;
-               rbuffer->uploaded = TRUE;
-               *const_offset = upload_offset;
-               return 0;
-       }
+       if ((*rbuffer)->user_buffer) {
+               uint8_t *ptr = (*rbuffer)->user_buffer;
+               unsigned size = (*rbuffer)->r.base.b.width0;
+               boolean flushed;
 
-       *const_offset = 0;
-       return 0;
+               *rbuffer = NULL;
+
+               u_upload_data(rctx->upload_const, 0, size, ptr, const_offset,
+                             (struct pipe_resource**)rbuffer, &flushed);
+       } else {
+               *const_offset = 0;
+       }
 }
index 9245dba576137abce42487655e504dffa9530dc6..824cf7fc46a55dd4e48c4e466de409b29d627e9a 100644 (file)
@@ -35,6 +35,7 @@
 #include <util/u_pack_color.h>
 #include <util/u_memory.h>
 #include <util/u_inlines.h>
+#include "util/u_upload_mgr.h"
 #include <pipebuffer/pb_buffer.h>
 #include "r600.h"
 #include "r600d.h"
@@ -68,8 +69,8 @@ static void r600_flush(struct pipe_context *ctx, unsigned flags,
 #endif
        r600_context_flush(&rctx->ctx);
 
-       r600_upload_flush(rctx->rupload_vb);
-       r600_upload_flush(rctx->rupload_const);
+       u_upload_flush(rctx->upload_vb);
+       u_upload_flush(rctx->upload_const);
 }
 
 static void r600_destroy_context(struct pipe_context *context)
@@ -88,8 +89,8 @@ static void r600_destroy_context(struct pipe_context *context)
                free(rctx->states[i]);
        }
 
-       r600_upload_destroy(rctx->rupload_vb);
-       r600_upload_destroy(rctx->rupload_const);
+       u_upload_destroy(rctx->upload_vb);
+       u_upload_destroy(rctx->upload_const);
 
        if (rctx->tran.translate_cache)
                translate_cache_destroy(rctx->tran.translate_cache);
@@ -167,14 +168,17 @@ static struct pipe_context *r600_create_context(struct pipe_screen *screen, void
                return NULL;
        }
 
-       rctx->rupload_vb = r600_upload_create(rctx, 128 * 1024, 16);
-       if (rctx->rupload_vb == NULL) {
+       rctx->upload_vb = u_upload_create(&rctx->context, 1024 * 1024, 16,
+                                         PIPE_BIND_VERTEX_BUFFER |
+                                         PIPE_BIND_INDEX_BUFFER);
+       if (rctx->upload_vb == NULL) {
                r600_destroy_context(&rctx->context);
                return NULL;
        }
 
-       rctx->rupload_const = r600_upload_create(rctx, 128 * 1024, 256);
-       if (rctx->rupload_const == NULL) {
+       rctx->upload_const = u_upload_create(&rctx->context, 1024 * 1024, 256,
+                                            PIPE_BIND_CONSTANT_BUFFER);
+       if (rctx->upload_const == NULL) {
                r600_destroy_context(&rctx->context);
                return NULL;
        }
index 7f74fda0daf7c200ec84453cc5ff4b0168949e2c..8d5e3c3b55337e7d1c9d00e82fb27dc9b88666eb 100644 (file)
@@ -131,8 +131,6 @@ struct r600_translate_context {
 #define R600_CONSTANT_ARRAY_SIZE 256
 #define R600_RESOURCE_ARRAY_SIZE 160
 
-struct r600_upload;
-
 struct r600_pipe_context {
        struct pipe_context             context;
        struct blitter_context          *blitter;
@@ -164,12 +162,12 @@ struct r600_pipe_context {
        /* shader information */
        unsigned                        sprite_coord_enable;
        bool                            flatshade;
-       struct r600_upload              *rupload_vb;
+       struct u_upload_mgr             *upload_vb;
        unsigned                        any_user_vbs;
        struct r600_textures_info       ps_samplers;
        unsigned                        vb_max_index;
        struct r600_translate_context   tran;
-       struct r600_upload              *rupload_const;
+       struct u_upload_mgr             *upload_const;
 };
 
 struct r600_drawl {
@@ -210,8 +208,8 @@ unsigned r600_buffer_is_referenced_by_cs(struct pipe_context *context,
                                         unsigned level, int layer);
 struct pipe_resource *r600_buffer_from_handle(struct pipe_screen *screen,
                                              struct winsys_handle *whandle);
-int r600_upload_index_buffer(struct r600_pipe_context *rctx, struct r600_drawl *draw);
-int r600_upload_user_buffers(struct r600_pipe_context *rctx);
+void r600_upload_index_buffer(struct r600_pipe_context *rctx, struct r600_drawl *draw);
+void r600_upload_user_buffers(struct r600_pipe_context *rctx);
 
 /* r600_query.c */
 void r600_init_query_functions(struct r600_pipe_context *rctx);
index 28b3e1e5e40b22e978a217c82b32d7f9babf9be2..6e302444712677fa835133e11763ffefa15c88a1 100644 (file)
@@ -71,7 +71,6 @@ struct r600_resource_buffer {
        struct r600_resource            r;
        uint32_t                        magic;
        void                            *user_buffer;
-       bool                            uploaded;
 };
 
 struct r600_surface {
@@ -98,10 +97,8 @@ static INLINE struct r600_resource_buffer *r600_buffer(struct pipe_resource *buf
        return NULL;
 }
 
-static INLINE boolean r600_buffer_is_user_buffer(struct pipe_resource *buffer)
+static INLINE boolean r600_is_user_buffer(struct pipe_resource *buffer)
 {
-       if (r600_buffer(buffer)->uploaded)
-               return FALSE;
        return r600_buffer(buffer)->user_buffer ? TRUE : FALSE;
 }
 
@@ -121,15 +118,7 @@ void r600_texture_transfer_unmap(struct pipe_context *ctx,
                                 struct pipe_transfer* transfer);
 
 struct r600_pipe_context;
-struct r600_upload *r600_upload_create(struct r600_pipe_context *rctx,
-                                       unsigned default_size,
-                                       unsigned alignment);
-void r600_upload_flush(struct r600_upload *upload);
-void r600_upload_destroy(struct r600_upload *upload);
-int r600_upload_buffer(struct r600_upload *upload, unsigned offset,
-                       unsigned size, struct r600_resource_buffer *in_buffer,
-                       unsigned *out_offset, unsigned *out_size,
-                       struct r600_bo **out_buffer);
-
-int r600_upload_const_buffer(struct r600_pipe_context *rctx, struct pipe_resource *cbuffer, uint32_t *offset);
+
+void r600_upload_const_buffer(struct r600_pipe_context *rctx, struct r600_resource_buffer **rbuffer, uint32_t *offset);
+
 #endif
index d678f42ad679f01573ce022b2ad9ef719e9da036..0191a119d5d6735405db7e54b371ef10138b865f 100644 (file)
@@ -1105,10 +1105,10 @@ static void r600_set_framebuffer_state(struct pipe_context *ctx,
 }
 
 static void r600_set_constant_buffer(struct pipe_context *ctx, uint shader, uint index,
-                                       struct pipe_resource *buffer)
+                                    struct pipe_resource *buffer)
 {
        struct r600_pipe_context *rctx = (struct r600_pipe_context *)ctx;
-       struct r600_resource *rbuffer = (struct r600_resource*)buffer;
+       struct r600_resource_buffer *rbuffer = r600_buffer(buffer);
        uint32_t offset;
 
        /* Note that the state tracker can unbind constant buffers by
@@ -1118,7 +1118,7 @@ static void r600_set_constant_buffer(struct pipe_context *ctx, uint shader, uint
                return;
        }
 
-       r600_upload_const_buffer(rctx, buffer, &offset);
+       r600_upload_const_buffer(rctx, &rbuffer, &offset);
 
        switch (shader) {
        case PIPE_SHADER_VERTEX:
@@ -1129,7 +1129,7 @@ static void r600_set_constant_buffer(struct pipe_context *ctx, uint shader, uint
                                        0xFFFFFFFF, NULL);
                r600_pipe_state_add_reg(&rctx->vs_const_buffer,
                                        R_028980_ALU_CONST_CACHE_VS_0,
-                                       (r600_bo_offset(rbuffer->bo) + offset) >> 8, 0xFFFFFFFF, rbuffer->bo);
+                                       (r600_bo_offset(rbuffer->r.bo) + offset) >> 8, 0xFFFFFFFF, rbuffer->r.bo);
                r600_context_pipe_state_set(&rctx->ctx, &rctx->vs_const_buffer);
                break;
        case PIPE_SHADER_FRAGMENT:
@@ -1140,13 +1140,16 @@ static void r600_set_constant_buffer(struct pipe_context *ctx, uint shader, uint
                                        0xFFFFFFFF, NULL);
                r600_pipe_state_add_reg(&rctx->ps_const_buffer,
                                        R_028940_ALU_CONST_CACHE_PS_0,
-                                       (r600_bo_offset(rbuffer->bo) + offset) >> 8, 0xFFFFFFFF, rbuffer->bo);
+                                       (r600_bo_offset(rbuffer->r.bo) + offset) >> 8, 0xFFFFFFFF, rbuffer->r.bo);
                r600_context_pipe_state_set(&rctx->ctx, &rctx->ps_const_buffer);
                break;
        default:
                R600_ERR("unsupported %d\n", shader);
                return;
        }
+
+       if (!rbuffer->user_buffer)
+               pipe_resource_reference((struct pipe_resource**)&rbuffer, NULL);
 }
 
 void r600_init_state_functions(struct r600_pipe_context *rctx)
index 3603376f738b9ffd1faa3537441fe72fbc5903ff..9c4fd3b16dcd80af35adc37388672f8b63e08215 100644 (file)
@@ -198,7 +198,7 @@ void r600_set_vertex_buffers(struct pipe_context *ctx, unsigned count,
                rctx->vertex_buffer[i].buffer = NULL;
                if (buffers[i].buffer == NULL)
                        continue;
-               if (r600_buffer_is_user_buffer(buffers[i].buffer))
+               if (r600_is_user_buffer(buffers[i].buffer))
                        rctx->any_user_vbs = TRUE;
                pipe_resource_reference(&rctx->vertex_buffer[i].buffer, buffers[i].buffer);
 
diff --git a/src/gallium/drivers/r600/r600_upload.c b/src/gallium/drivers/r600/r600_upload.c
deleted file mode 100644 (file)
index 44102ff..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright 2010 Jerome Glisse <glisse@freedesktop.org>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * on the rights to use, copy, modify, merge, publish, distribute, sub
- * license, and/or sell copies of the Software, and to permit persons to whom
- * the Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
- * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
- * USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *      Jerome Glisse <jglisse@redhat.com>
- */
-#include <errno.h>
-#include "util/u_inlines.h"
-#include "util/u_memory.h"
-#include "r600.h"
-#include "r600_pipe.h"
-#include "r600_resource.h"
-
-struct r600_upload {
-       struct r600_pipe_context        *rctx;
-       struct r600_bo                  *buffer;
-       char                            *ptr;
-       unsigned                        size;
-       unsigned                        default_size;
-       unsigned                        total_alloc_size;
-       unsigned                        offset;
-       unsigned                        alignment;
-};
-
-struct r600_upload *r600_upload_create(struct r600_pipe_context *rctx,
-                                       unsigned default_size,
-                                       unsigned alignment)
-{
-       struct r600_upload *upload = CALLOC_STRUCT(r600_upload);
-
-       if (upload == NULL)
-               return NULL;
-
-       upload->rctx = rctx;
-       upload->size = 0;
-       upload->default_size = default_size;
-       upload->alignment = alignment;
-       upload->ptr = NULL;
-       upload->buffer = NULL;
-       upload->total_alloc_size = 0;
-
-       return upload;
-}
-
-void r600_upload_flush(struct r600_upload *upload)
-{
-       if (upload->buffer) {
-               r600_bo_reference(upload->rctx->radeon, &upload->buffer, NULL);
-       }
-       upload->default_size = MAX2(upload->total_alloc_size, upload->default_size);
-       upload->total_alloc_size = 0;
-       upload->size = 0;
-       upload->offset = 0;
-       upload->ptr = NULL;
-       upload->buffer = NULL;
-}
-
-void r600_upload_destroy(struct r600_upload *upload)
-{
-       r600_upload_flush(upload);
-       FREE(upload);
-}
-
-int r600_upload_buffer(struct r600_upload *upload, unsigned offset,
-                       unsigned size, struct r600_resource_buffer *in_buffer,
-                       unsigned *out_offset, unsigned *out_size,
-                       struct r600_bo **out_buffer)
-{
-       unsigned alloc_size = align(size, upload->alignment);
-       const void *in_ptr = NULL;
-
-       if (upload->offset + alloc_size > upload->size) {
-               if (upload->size) {
-                       r600_bo_reference(upload->rctx->radeon, &upload->buffer, NULL);
-               }
-               upload->size = align(MAX2(upload->default_size, alloc_size), 4096);
-               upload->total_alloc_size += upload->size;
-               upload->offset = 0;
-               upload->buffer = r600_bo(upload->rctx->radeon, upload->size, 4096, PIPE_BIND_VERTEX_BUFFER, 0);
-               if (upload->buffer == NULL) {
-                       return -ENOMEM;
-               }
-               upload->ptr = r600_bo_map(upload->rctx->radeon, upload->buffer, 0, NULL);
-       }
-
-       in_ptr = in_buffer->user_buffer;
-       memcpy(upload->ptr + upload->offset, (uint8_t *) in_ptr + offset, size);
-       *out_offset = upload->offset;
-       *out_size = upload->size;
-       *out_buffer = NULL;
-       r600_bo_reference(upload->rctx->radeon, out_buffer, upload->buffer);
-       upload->offset += alloc_size;
-
-       return 0;
-}