util: Make helper functions for pack/unpacking pixel rows.
[mesa.git] / src / gallium / drivers / r600 / r600_texture.c
index ee6ed64b9f20784cb281eab7eec47289ff380427..ad94c9fb0f04edda83eaf25270a5dbc28d681a15 100644 (file)
 #include "r600_pipe_common.h"
 #include "r600_cs.h"
 #include "r600_query.h"
-#include "util/u_format.h"
+#include "util/format/u_format.h"
 #include "util/u_log.h"
 #include "util/u_memory.h"
 #include "util/u_pack_color.h"
 #include "util/u_surface.h"
 #include "util/os_time.h"
+#include "state_tracker/winsys_handle.h"
 #include <errno.h>
 #include <inttypes.h>
 
@@ -178,7 +179,8 @@ static unsigned r600_texture_get_offset(struct r600_common_screen *rscreen,
 {
        *stride = rtex->surface.u.legacy.level[level].nblk_x *
                rtex->surface.bpe;
-       *layer_stride = rtex->surface.u.legacy.level[level].slice_size;
+       assert((uint64_t)rtex->surface.u.legacy.level[level].slice_size_dw * 4 <= UINT_MAX);
+       *layer_stride = (uint64_t)rtex->surface.u.legacy.level[level].slice_size_dw * 4;
 
        if (!box)
                return rtex->surface.u.legacy.level[level].offset;
@@ -186,7 +188,7 @@ static unsigned r600_texture_get_offset(struct r600_common_screen *rscreen,
        /* Each texture is an array of mipmap levels. Each level is
         * an array of slices. */
        return rtex->surface.u.legacy.level[level].offset +
-               box->z * rtex->surface.u.legacy.level[level].slice_size +
+               box->z * (uint64_t)rtex->surface.u.legacy.level[level].slice_size_dw * 4 +
                (box->y / rtex->surface.blk_h *
                 rtex->surface.u.legacy.level[level].nblk_x +
                 box->x / rtex->surface.blk_w) * rtex->surface.bpe;
@@ -216,7 +218,7 @@ static int r600_init_surface(struct r600_common_screen *rscreen,
                bpe = 4; /* stencil is allocated separately on evergreen */
        } else {
                bpe = util_format_get_blocksize(ptex->format);
-               assert(util_is_power_of_two(bpe));
+               assert(util_is_power_of_two_or_zero(bpe));
        }
 
        if (!is_flushed_depth && is_depth) {
@@ -244,8 +246,8 @@ static int r600_init_surface(struct r600_common_screen *rscreen,
        if (!(ptex->flags & R600_RESOURCE_FLAG_FORCE_TILING))
                flags |= RADEON_SURF_OPTIMIZE_FOR_SPACE;
 
-       r = rscreen->ws->surface_init(rscreen->ws, ptex, flags, bpe,
-                                     array_mode, surface);
+       r = rscreen->ws->surface_init(rscreen->ws, ptex,
+                                     flags, bpe, array_mode, surface);
        if (r) {
                return r;
        }
@@ -256,8 +258,8 @@ static int r600_init_surface(struct r600_common_screen *rscreen,
                 * for those
                 */
                surface->u.legacy.level[0].nblk_x = pitch_in_bytes_override / bpe;
-               surface->u.legacy.level[0].slice_size = pitch_in_bytes_override *
-                       surface->u.legacy.level[0].nblk_y;
+               surface->u.legacy.level[0].slice_size_dw =
+                       ((uint64_t)pitch_in_bytes_override * surface->u.legacy.level[0].nblk_y) / 4;
        }
 
        if (offset) {
@@ -365,7 +367,7 @@ static void r600_reallocate_texture_inplace(struct r600_common_context *rctx,
        templ.bind |= new_bind_flag;
 
        /* r600g doesn't react to dirty_tex_descriptor_counter */
-       if (rctx->chip_class < SI)
+       if (rctx->chip_class < GFX6)
                return;
 
        if (rtex->resource.b.is_shared)
@@ -392,7 +394,7 @@ static void r600_reallocate_texture_inplace(struct r600_common_context *rctx,
 
                        u_box_3d(0, 0, 0,
                                 u_minify(templ.width0, i), u_minify(templ.height0, i),
-                                util_max_layer(&templ, i) + 1, &box);
+                                util_num_layers(&templ, i), &box);
 
                        rctx->dma_copy(&rctx->b, &new_tex->resource.b.b, i, 0, 0, 0,
                                       &rtex->resource.b.b, i, &box);
@@ -441,11 +443,37 @@ static void r600_reallocate_texture_inplace(struct r600_common_context *rctx,
        p_atomic_inc(&rctx->screen->dirty_tex_counter);
 }
 
-static boolean r600_texture_get_handle(struct pipe_screen* screen,
-                                      struct pipe_context *ctx,
-                                      struct pipe_resource *resource,
-                                      struct winsys_handle *whandle,
-                                       unsigned usage)
+static void r600_texture_get_info(struct pipe_screen* screen,
+                                 struct pipe_resource *resource,
+                                 unsigned *pstride,
+                                 unsigned *poffset)
+{
+       struct r600_common_screen *rscreen = (struct r600_common_screen*)screen;
+       struct r600_texture *rtex = (struct r600_texture*)resource;
+       unsigned stride = 0;
+       unsigned offset = 0;
+
+       if (!rscreen || !rtex)
+               return;
+
+       if (resource->target != PIPE_BUFFER) {
+               offset = rtex->surface.u.legacy.level[0].offset;
+               stride = rtex->surface.u.legacy.level[0].nblk_x *
+                        rtex->surface.bpe;
+       }
+
+       if (pstride)
+               *pstride = stride;
+
+       if (poffset)
+               *poffset = offset;
+}
+
+static bool r600_texture_get_handle(struct pipe_screen* screen,
+                                   struct pipe_context *ctx,
+                                   struct pipe_resource *resource,
+                                   struct winsys_handle *whandle,
+                                   unsigned usage)
 {
        struct r600_common_screen *rscreen = (struct r600_common_screen*)screen;
        struct r600_common_context *rctx;
@@ -492,17 +520,11 @@ static boolean r600_texture_get_handle(struct pipe_screen* screen,
                /* Set metadata. */
                if (!res->b.is_shared || update_metadata) {
                        r600_texture_init_metadata(rscreen, rtex, &metadata);
-                       if (rscreen->query_opaque_metadata)
-                               rscreen->query_opaque_metadata(rscreen, rtex,
-                                                              &metadata);
 
                        rscreen->ws->buffer_set_metadata(res->buf, &metadata);
                }
 
-               offset = rtex->surface.u.legacy.level[0].offset;
-               stride = rtex->surface.u.legacy.level[0].nblk_x *
-                       rtex->surface.bpe;
-               slice_size = rtex->surface.u.legacy.level[0].slice_size;
+               slice_size = (uint64_t)rtex->surface.u.legacy.level[0].slice_size_dw * 4;
        } else {
                /* Move a suballocated buffer into a non-suballocated allocation. */
                if (rscreen->ws->buffer_is_suballocated(res->buf)) {
@@ -531,11 +553,11 @@ static boolean r600_texture_get_handle(struct pipe_screen* screen,
                }
 
                /* Buffers */
-               offset = 0;
-               stride = 0;
                slice_size = 0;
        }
 
+       r600_texture_get_info(screen, resource, &stride, &offset);
+
        if (res->b.is_shared) {
                /* USAGE_EXPLICIT_FLUSH must be cleared if at least one user
                 * doesn't set it.
@@ -548,8 +570,10 @@ static boolean r600_texture_get_handle(struct pipe_screen* screen,
                res->external_usage = usage;
        }
 
-       return rscreen->ws->buffer_get_handle(res->buf, stride, offset,
-                                             slice_size, whandle);
+       whandle->stride = stride;
+       whandle->offset = offset + slice_size * whandle->layer;
+
+       return rscreen->ws->buffer_get_handle(rscreen->ws, res->buf, whandle);
 }
 
 static void r600_texture_destroy(struct pipe_screen *screen,
@@ -615,8 +639,8 @@ void r600_texture_get_fmask_info(struct r600_common_screen *rscreen,
                bpe *= 2;
        }
 
-       if (rscreen->ws->surface_init(rscreen->ws, &templ, flags, bpe,
-                                     RADEON_SURF_MODE_2D, &fmask)) {
+       if (rscreen->ws->surface_init(rscreen->ws, &templ,
+                                     flags, bpe, RADEON_SURF_MODE_2D, &fmask)) {
                R600_ERR("Got error in surface_init while allocating FMASK.\n");
                return;
        }
@@ -675,7 +699,7 @@ void r600_texture_get_cmask_info(struct r600_common_screen *rscreen,
 
        out->slice_tile_max = ((pitch_elements * height) / (128*128)) - 1;
        out->alignment = MAX2(256, base_align);
-       out->size = (util_max_layer(&rtex->resource.b.b, 0) + 1) *
+       out->size = util_num_layers(&rtex->resource.b.b, 0) *
                    align(slice_bytes, base_align);
 }
 
@@ -738,7 +762,7 @@ static void r600_texture_get_htile_size(struct r600_common_screen *rscreen,
        rtex->surface.htile_size = 0;
 
        if (rscreen->chip_class <= EVERGREEN &&
-           rscreen->info.drm_major == 2 && rscreen->info.drm_minor < 26)
+           rscreen->info.drm_minor < 26)
                return;
 
        /* HW bug on R6xx. */
@@ -773,8 +797,8 @@ static void r600_texture_get_htile_size(struct r600_common_screen *rscreen,
                return;
        }
 
-       width = align(rtex->resource.b.b.width0, cl_width * 8);
-       height = align(rtex->resource.b.b.height0, cl_height * 8);
+       width = align(rtex->surface.u.legacy.level[0].nblk_x, cl_width * 8);
+       height = align(rtex->surface.u.legacy.level[0].nblk_y, cl_height * 8);
 
        slice_elements = (width * height) / (8 * 8);
        slice_bytes = slice_elements * 4;
@@ -784,7 +808,7 @@ static void r600_texture_get_htile_size(struct r600_common_screen *rscreen,
 
        rtex->surface.htile_alignment = base_align;
        rtex->surface.htile_size =
-               (util_max_layer(&rtex->resource.b.b, 0) + 1) *
+               util_num_layers(&rtex->resource.b.b, 0) *
                align(slice_bytes, base_align);
 }
 
@@ -837,7 +861,7 @@ void r600_print_texture_info(struct r600_common_screen *rscreen,
                        rtex->cmask.slice_tile_max);
 
        if (rtex->htile_offset)
-               u_log_printf(log, "  HTile: offset=%"PRIu64", size=%"PRIu64", "
+               u_log_printf(log, "  HTile: offset=%"PRIu64", size=%u "
                        "alignment=%u\n",
                             rtex->htile_offset, rtex->surface.htile_size,
                             rtex->surface.htile_alignment);
@@ -847,7 +871,7 @@ void r600_print_texture_info(struct r600_common_screen *rscreen,
                        "npix_x=%u, npix_y=%u, npix_z=%u, nblk_x=%u, nblk_y=%u, "
                        "mode=%u, tiling_index = %u\n",
                        i, rtex->surface.u.legacy.level[i].offset,
-                       rtex->surface.u.legacy.level[i].slice_size,
+                       (uint64_t)rtex->surface.u.legacy.level[i].slice_size_dw * 4,
                        u_minify(rtex->resource.b.b.width0, i),
                        u_minify(rtex->resource.b.b.height0, i),
                        u_minify(rtex->resource.b.b.depth0, i),
@@ -865,7 +889,7 @@ void r600_print_texture_info(struct r600_common_screen *rscreen,
                                "npix_y=%u, npix_z=%u, nblk_x=%u, nblk_y=%u, "
                                "mode=%u, tiling_index = %u\n",
                                i, rtex->surface.u.legacy.stencil_level[i].offset,
-                               rtex->surface.u.legacy.stencil_level[i].slice_size,
+                               (uint64_t)rtex->surface.u.legacy.stencil_level[i].slice_size_dw * 4,
                                u_minify(rtex->resource.b.b.width0, i),
                                u_minify(rtex->resource.b.b.height0, i),
                                u_minify(rtex->resource.b.b.depth0, i),
@@ -952,10 +976,6 @@ r600_texture_create_object(struct pipe_screen *screen,
                r600_init_resource_fields(rscreen, resource, rtex->size,
                                          rtex->surface.surf_alignment);
 
-               /* Displayable surfaces are not suballocated. */
-               if (resource->b.b.bind & PIPE_BIND_SCANOUT)
-                       resource->flags |= RADEON_FLAG_NO_SUBALLOC;
-
                if (!r600_alloc_resource(rscreen, resource)) {
                        FREE(rtex);
                        return NULL;
@@ -995,7 +1015,7 @@ r600_texture_create_object(struct pipe_screen *screen,
                fprintf(stderr, "VM start=0x%"PRIX64"  end=0x%"PRIX64" | Texture %ix%ix%i, %i levels, %i samples, %s\n",
                        rtex->resource.gpu_address,
                        rtex->resource.gpu_address + rtex->resource.buf->size,
-                       base->width0, base->height0, util_max_layer(base, 0)+1, base->last_level+1,
+                       base->width0, base->height0, util_num_layers(base, 0), base->last_level+1,
                        base->nr_samples ? base->nr_samples : 1, util_format_short_name(base->format));
        }
 
@@ -1052,12 +1072,9 @@ r600_choose_tiling(struct r600_common_screen *rscreen,
                if (templ->bind & PIPE_BIND_LINEAR)
                        return RADEON_SURF_MODE_LINEAR_ALIGNED;
 
-               /* Textures with a very small height are recommended to be linear. */
+               /* 1D textures should be linear - fixes image operations on 1d */
                if (templ->target == PIPE_TEXTURE_1D ||
-                   templ->target == PIPE_TEXTURE_1D_ARRAY ||
-                   /* Only very thin and long 2D textures should benefit from
-                    * linear_aligned. */
-                   (templ->width0 > 8 && templ->height0 <= 2))
+                   templ->target == PIPE_TEXTURE_1D_ARRAY)
                        return RADEON_SURF_MODE_LINEAR_ALIGNED;
 
                /* Textures likely to be mapped often. */
@@ -1101,7 +1118,6 @@ static struct pipe_resource *r600_texture_from_handle(struct pipe_screen *screen
 {
        struct r600_common_screen *rscreen = (struct r600_common_screen*)screen;
        struct pb_buffer *buf = NULL;
-       unsigned stride = 0, offset = 0;
        enum radeon_surf_mode array_mode;
        struct radeon_surf surface = {};
        int r;
@@ -1114,7 +1130,8 @@ static struct pipe_resource *r600_texture_from_handle(struct pipe_screen *screen
              templ->depth0 != 1 || templ->last_level != 0)
                return NULL;
 
-       buf = rscreen->ws->buffer_from_handle(rscreen->ws, whandle, &stride, &offset);
+       buf = rscreen->ws->buffer_from_handle(rscreen->ws, whandle,
+                                             rscreen->info.max_alignment);
        if (!buf)
                return NULL;
 
@@ -1122,8 +1139,9 @@ static struct pipe_resource *r600_texture_from_handle(struct pipe_screen *screen
        r600_surface_import_metadata(rscreen, &surface, &metadata,
                                     &array_mode, &is_scanout);
 
-       r = r600_init_surface(rscreen, &surface, templ, array_mode, stride,
-                             offset, true, is_scanout, false);
+       r = r600_init_surface(rscreen, &surface, templ, array_mode,
+                             whandle->stride, whandle->offset,
+                             true, is_scanout, false);
        if (r) {
                return NULL;
        }
@@ -1135,9 +1153,6 @@ static struct pipe_resource *r600_texture_from_handle(struct pipe_screen *screen
        rtex->resource.b.is_shared = true;
        rtex->resource.external_usage = usage;
 
-       if (rscreen->apply_opaque_metadata)
-               rscreen->apply_opaque_metadata(rscreen, rtex, &metadata);
-
        assert(rtex->surface.tile_swizzle == 0);
        return &rtex->resource.b.b;
 }
@@ -1245,7 +1260,7 @@ static bool r600_can_invalidate_texture(struct r600_common_screen *rscreen,
                                        const struct pipe_box *box)
 {
        /* r600g doesn't react to dirty_tex_descriptor_counter */
-       return rscreen->chip_class >= SI &&
+       return rscreen->chip_class >= GFX6 &&
                !rtex->resource.b.is_shared &&
                !(transfer_usage & PIPE_TRANSFER_READ) &&
                rtex->resource.b.b.last_level == 0 &&
@@ -1499,7 +1514,7 @@ static void r600_texture_transfer_unmap(struct pipe_context *ctx,
         * The result is that the kernel memory manager is never a bottleneck.
         */
        if (rctx->num_alloc_tex_transfer_bytes > rctx->screen->info.gart_size / 4) {
-               rctx->gfx.flush(rctx, RADEON_FLUSH_ASYNC, NULL);
+               rctx->gfx.flush(rctx, PIPE_FLUSH_ASYNC, NULL);
                rctx->num_alloc_tex_transfer_bytes = 0;
        }
 
@@ -1620,11 +1635,11 @@ static void r600_clear_texture(struct pipe_context *pipe,
 
                /* Depth is always present. */
                clear = PIPE_CLEAR_DEPTH;
-               desc->unpack_z_float(&depth, 0, data, 0, 1, 1);
+               util_format_unpack_z_float(tex->format, &depth, data, 1);
 
                if (rtex->surface.has_stencil) {
                        clear |= PIPE_CLEAR_STENCIL;
-                       desc->unpack_s_8uint(&stencil, 0, data, 0, 1, 1);
+                       util_format_unpack_s_8uint(tex->format, &stencil, data, 1);
                }
 
                pipe->clear_depth_stencil(pipe, sf, clear, depth, stencil,
@@ -1633,16 +1648,10 @@ static void r600_clear_texture(struct pipe_context *pipe,
        } else {
                union pipe_color_union color;
 
-               /* pipe_color_union requires the full vec4 representation. */
-               if (util_format_is_pure_uint(tex->format))
-                       desc->unpack_rgba_uint(color.ui, 0, data, 0, 1, 1);
-               else if (util_format_is_pure_sint(tex->format))
-                       desc->unpack_rgba_sint(color.i, 0, data, 0, 1, 1);
-               else
-                       desc->unpack_rgba_float(color.f, 0, data, 0, 1, 1);
+               util_format_unpack_rgba(tex->format, color.ui, data, 1);
 
                if (screen->is_format_supported(screen, tex->format,
-                                               tex->target, 0,
+                                               tex->target, 0, 0,
                                                PIPE_BIND_RENDER_TARGET)) {
                        pipe->clear_render_target(pipe, sf, &color,
                                                  box->x, box->y,
@@ -1756,7 +1765,7 @@ void evergreen_do_fast_color_clear(struct r600_common_context *rctx,
        int i;
 
        /* This function is broken in BE, so just disable this path for now */
-#ifdef PIPE_ARCH_BIG_ENDIAN
+#if UTIL_ARCH_BIG_ENDIAN
        return;
 #endif
 
@@ -1800,6 +1809,16 @@ void evergreen_do_fast_color_clear(struct r600_common_context *rctx,
                    !(tex->resource.external_usage & PIPE_HANDLE_USAGE_EXPLICIT_FLUSH))
                        continue;
 
+               /* Use a slow clear for small surfaces where the cost of
+                * the eliminate pass can be higher than the benefit of fast
+                * clear. AMDGPU-pro does this, but the numbers may differ.
+                *
+                * This helps on both dGPUs and APUs, even small ones.
+                */
+               if (tex->resource.b.b.nr_samples <= 1 &&
+                   tex->resource.b.b.width0 * tex->resource.b.b.height0 <= 300 * 300)
+                       continue;
+
                {
                        /* 128-bit formats are unusupported */
                        if (tex->surface.bpe > 8) {
@@ -1842,13 +1861,12 @@ r600_memobj_from_handle(struct pipe_screen *screen,
        struct r600_common_screen *rscreen = (struct r600_common_screen*)screen;
        struct r600_memory_object *memobj = CALLOC_STRUCT(r600_memory_object);
        struct pb_buffer *buf = NULL;
-       uint32_t stride, offset;
 
        if (!memobj)
                return NULL;
 
        buf = rscreen->ws->buffer_from_handle(rscreen->ws, whandle,
-                                             &stride, &offset);
+                                             rscreen->info.max_alignment);
        if (!buf) {
                free(memobj);
                return NULL;
@@ -1856,8 +1874,8 @@ r600_memobj_from_handle(struct pipe_screen *screen,
 
        memobj->b.dedicated = dedicated;
        memobj->buf = buf;
-       memobj->stride = stride;
-       memobj->offset = offset;
+       memobj->stride = whandle->stride;
+       memobj->offset = whandle->offset;
 
        return (struct pipe_memory_object *)memobj;
 
@@ -1938,10 +1956,7 @@ r600_texture_from_memobj(struct pipe_screen *screen,
        pb_reference(&buf, memobj->buf);
 
        rtex->resource.b.is_shared = true;
-       rtex->resource.external_usage = PIPE_HANDLE_USAGE_READ_WRITE;
-
-       if (rscreen->apply_opaque_metadata)
-               rscreen->apply_opaque_metadata(rscreen, rtex, &metadata);
+       rtex->resource.external_usage = PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE;
 
        return &rtex->resource.b.b;
 }
@@ -1950,6 +1965,7 @@ void r600_init_screen_texture_functions(struct r600_common_screen *rscreen)
 {
        rscreen->b.resource_from_handle = r600_texture_from_handle;
        rscreen->b.resource_get_handle = r600_texture_get_handle;
+       rscreen->b.resource_get_info = r600_texture_get_info;
        rscreen->b.resource_from_memobj = r600_texture_from_memobj;
        rscreen->b.memobj_create_from_handle = r600_memobj_from_handle;
        rscreen->b.memobj_destroy = r600_memobj_destroy;