r600g,radeonsi: consolidate create_surface and surface_destroy
[mesa.git] / src / gallium / drivers / radeon / r600_texture.c
index 26eee12c80485ab4bf1ed0af9675e5b14caa9189..35ad97bd14163e74b5d22cd394b06cfa175493c3 100644 (file)
@@ -29,6 +29,7 @@
 #include "util/u_format.h"
 #include "util/u_memory.h"
 #include <errno.h>
+#include <inttypes.h>
 
 /* Same as resource_copy_region, except that both upsampling and downsampling are allowed. */
 static void r600_copy_region_with_blit(struct pipe_context *pipe,
@@ -235,8 +236,8 @@ static int r600_setup_surface(struct pipe_screen *screen,
 }
 
 static boolean r600_texture_get_handle(struct pipe_screen* screen,
-                                       struct pipe_resource *ptex,
-                                       struct winsys_handle *whandle)
+                                      struct pipe_resource *ptex,
+                                      struct winsys_handle *whandle)
 {
        struct r600_texture *rtex = (struct r600_texture*)ptex;
        struct r600_resource *resource = &rtex->resource;
@@ -253,7 +254,8 @@ static boolean r600_texture_get_handle(struct pipe_screen* screen,
                                       surface->tile_split,
                                       surface->stencil_tile_split,
                                       surface->mtilea,
-                                      surface->level[0].pitch_bytes);
+                                      surface->level[0].pitch_bytes,
+                                      (surface->flags & RADEON_SURF_SCANOUT) != 0);
 
        return rscreen->ws->buffer_get_handle(resource->buf,
                                                surface->level[0].pitch_bytes, whandle);
@@ -268,7 +270,7 @@ static void r600_texture_destroy(struct pipe_screen *screen,
        if (rtex->flushed_depth_texture)
                pipe_resource_reference((struct pipe_resource **)&rtex->flushed_depth_texture, NULL);
 
-       pipe_resource_reference((struct pipe_resource**)&rtex->htile, NULL);
+       pipe_resource_reference((struct pipe_resource**)&rtex->htile_buffer, NULL);
        if (rtex->cmask_buffer != &rtex->resource) {
            pipe_resource_reference((struct pipe_resource**)&rtex->cmask_buffer, NULL);
        }
@@ -403,6 +405,10 @@ static void si_texture_get_cmask_info(struct r600_common_screen *rscreen,
                cl_width = 64;
                cl_height = 32;
                break;
+       case 16: /* Hawaii */
+               cl_width = 64;
+               cl_height = 64;
+               break;
        default:
                assert(0);
                return;
@@ -447,26 +453,72 @@ void r600_texture_init_cmask(struct r600_common_screen *rscreen,
 
        rtex->cmask_buffer = (struct r600_resource *)
                pipe_buffer_create(&rscreen->b, PIPE_BIND_CUSTOM,
-                                  PIPE_USAGE_STATIC, rtex->cmask.size);
+                                  PIPE_USAGE_DEFAULT, rtex->cmask.size);
        if (rtex->cmask_buffer == NULL) {
                rtex->cmask.size = 0;
        }
 }
 
-static void r600_texture_allocate_htile(struct r600_common_screen *rscreen,
-                                       struct r600_texture *rtex)
+static unsigned si_texture_htile_alloc_size(struct r600_common_screen *rscreen,
+                                           struct r600_texture *rtex)
+{
+       unsigned cl_width, cl_height, width, height;
+       unsigned slice_elements, slice_bytes, pipe_interleave_bytes, base_align;
+       unsigned num_pipes = rscreen->tiling_info.num_channels;
+
+       /* HTILE doesn't work with 1D tiling (there's massive corruption
+        * in glxgears). */
+       if (rtex->surface.level[0].mode != RADEON_SURF_MODE_2D)
+               return 0;
+
+       switch (num_pipes) {
+       case 2:
+               cl_width = 32;
+               cl_height = 32;
+               break;
+       case 4:
+               cl_width = 64;
+               cl_height = 32;
+               break;
+       case 8:
+               cl_width = 64;
+               cl_height = 64;
+               break;
+       case 16:
+               cl_width = 128;
+               cl_height = 64;
+               break;
+       default:
+               assert(0);
+               return 0;
+       }
+
+       width = align(rtex->surface.npix_x, cl_width * 8);
+       height = align(rtex->surface.npix_y, cl_height * 8);
+
+       slice_elements = (width * height) / (8 * 8);
+       slice_bytes = slice_elements * 4;
+
+       pipe_interleave_bytes = rscreen->tiling_info.group_bytes;
+       base_align = num_pipes * pipe_interleave_bytes;
+
+       return rtex->surface.array_size * align(slice_bytes, base_align);
+}
+
+static unsigned r600_texture_htile_alloc_size(struct r600_common_screen *rscreen,
+                                             struct r600_texture *rtex)
 {
        unsigned sw = rtex->surface.level[0].nblk_x * rtex->surface.blk_w;
        unsigned sh = rtex->surface.level[0].nblk_y * rtex->surface.blk_h;
-       unsigned htile_size;
        unsigned npipes = rscreen->info.r600_num_tile_pipes;
+       unsigned htile_size;
 
        /* XXX also use it for other texture targets */
        if (rscreen->info.drm_minor < 26 ||
            rtex->resource.b.b.target != PIPE_TEXTURE_2D ||
            rtex->surface.level[0].nblk_x < 32 ||
            rtex->surface.level[0].nblk_y < 32) {
-               return;
+               return 0;
        }
 
        /* this alignment and htile size only apply to linear htile buffer */
@@ -475,20 +527,36 @@ static void r600_texture_allocate_htile(struct r600_common_screen *rscreen,
        htile_size = (sw >> 3) * (sh >> 3) * 4;
        /* must be aligned with 2K * npipes */
        htile_size = align(htile_size, (2 << 10) * npipes);
+       return htile_size;
+}
+
+static void r600_texture_allocate_htile(struct r600_common_screen *rscreen,
+                                       struct r600_texture *rtex)
+{
+       unsigned htile_size;
+       if (rscreen->chip_class >= SI) {
+               htile_size = si_texture_htile_alloc_size(rscreen, rtex);
+       } else {
+               htile_size = r600_texture_htile_alloc_size(rscreen, rtex);
+       }
+
+       if (!htile_size)
+               return;
 
        /* XXX don't allocate it separately */
-       rtex->htile = (struct r600_resource*)pipe_buffer_create(&rscreen->b, PIPE_BIND_CUSTOM,
-                                                               PIPE_USAGE_STATIC, htile_size);
-       if (rtex->htile == NULL) {
+       rtex->htile_buffer = (struct r600_resource*)
+                            pipe_buffer_create(&rscreen->b, PIPE_BIND_CUSTOM,
+                                               PIPE_USAGE_DEFAULT, htile_size);
+       if (rtex->htile_buffer == NULL) {
                /* this is not a fatal error as we can still keep rendering
-                * without htile buffer
-                */
-               R600_ERR("r600: failed to create bo for htile buffers\n");
+                * without htile buffer */
+               R600_ERR("Failed to create buffer object for htile buffer.\n");
        } else {
-               r600_screen_clear_buffer(rscreen, &rtex->htile->b.b, 0, htile_size, 0);
+               r600_screen_clear_buffer(rscreen, &rtex->htile_buffer->b.b, 0, htile_size, 0);
        }
 }
 
+/* Common processing for r600_texture_create and r600_texture_from_handle */
 static struct r600_texture *
 r600_texture_create_object(struct pipe_screen *screen,
                           const struct pipe_resource *base,
@@ -499,7 +567,6 @@ r600_texture_create_object(struct pipe_screen *screen,
        struct r600_texture *rtex;
        struct r600_resource *resource;
        struct r600_common_screen *rscreen = (struct r600_common_screen*)screen;
-       int r;
 
        rtex = CALLOC_STRUCT(r600_texture);
        if (rtex == NULL)
@@ -515,48 +582,42 @@ r600_texture_create_object(struct pipe_screen *screen,
        /* don't include stencil-only formats which we don't support for rendering */
        rtex->is_depth = util_format_has_depth(util_format_description(rtex->resource.b.b.format));
 
-       /* Tiled depth textures utilize the non-displayable tile order.
-        * Applies to R600-Cayman. */
-       rtex->non_disp_tiling = rtex->is_depth && rtex->surface.level[0].mode >= RADEON_SURF_MODE_1D;
-
        rtex->surface = *surface;
-       r = r600_setup_surface(screen, rtex, pitch_in_bytes_override);
-       if (r) {
+       if (r600_setup_surface(screen, rtex, pitch_in_bytes_override)) {
                FREE(rtex);
                return NULL;
        }
 
-       if (base->nr_samples > 1 && !rtex->is_depth && !buf) {
-               r600_texture_allocate_fmask(rscreen, rtex);
-               r600_texture_allocate_cmask(rscreen, rtex);
-               rtex->cmask_buffer = &rtex->resource;
-       }
+       /* Tiled depth textures utilize the non-displayable tile order.
+        * This must be done after r600_setup_surface.
+        * Applies to R600-Cayman. */
+       rtex->non_disp_tiling = rtex->is_depth && rtex->surface.level[0].mode >= RADEON_SURF_MODE_1D;
 
-       if (!rtex->is_depth && base->nr_samples > 1 &&
-           (!rtex->fmask.size || !rtex->cmask.size)) {
-               FREE(rtex);
-               return NULL;
-       }
+       if (rtex->is_depth) {
+               if (!(base->flags & (R600_RESOURCE_FLAG_TRANSFER |
+                                    R600_RESOURCE_FLAG_FLUSHED_DEPTH)) &&
+                   (rscreen->debug_flags & DBG_HYPERZ)) {
 
-       if (rtex->is_depth &&
-           !(base->flags & (R600_RESOURCE_FLAG_TRANSFER |
-                            R600_RESOURCE_FLAG_FLUSHED_DEPTH)) &&
-           !(rscreen->debug_flags & DBG_NO_HYPERZ)) {
-               if (rscreen->chip_class >= SI) {
-                       /* XXX implement Hyper-Z for SI.
-                        * Reuse the CMASK allocator, which is almost the same as HTILE. */
-               } else {
                        r600_texture_allocate_htile(rscreen, rtex);
                }
+       } else {
+               if (base->nr_samples > 1) {
+                       if (!buf) {
+                               r600_texture_allocate_fmask(rscreen, rtex);
+                               r600_texture_allocate_cmask(rscreen, rtex);
+                               rtex->cmask_buffer = &rtex->resource;
+                       }
+                       if (!rtex->fmask.size || !rtex->cmask.size) {
+                               FREE(rtex);
+                               return NULL;
+                       }
+               }
        }
 
        /* Now create the backing buffer. */
        if (!buf) {
-               unsigned base_align = rtex->surface.bo_alignment;
-               unsigned usage = rtex->surface.level[0].mode >= RADEON_SURF_MODE_1D ?
-                                        PIPE_USAGE_STATIC : base->usage;
-
-               if (!r600_init_resource(rscreen, resource, rtex->size, base_align, FALSE, usage)) {
+               if (!r600_init_resource(rscreen, resource, rtex->size,
+                                       rtex->surface.bo_alignment, FALSE)) {
                        FREE(rtex);
                        return NULL;
                }
@@ -573,43 +634,42 @@ r600_texture_create_object(struct pipe_screen *screen,
        }
 
        if (rscreen->debug_flags & DBG_VM) {
-               fprintf(stderr, "VM start=0x%llX  end=0x%llX | Texture %ix%ix%i, %i levels, %i samples, %s\n",
+               fprintf(stderr, "VM start=0x%"PRIu64"  end=0x%"PRIu64" | Texture %ix%ix%i, %i levels, %i samples, %s\n",
                        r600_resource_va(screen, &rtex->resource.b.b),
                        r600_resource_va(screen, &rtex->resource.b.b) + rtex->resource.buf->size,
                        base->width0, base->height0, util_max_layer(base, 0)+1, base->last_level+1,
                        base->nr_samples ? base->nr_samples : 1, util_format_short_name(base->format));
        }
 
-       if (rscreen->debug_flags & DBG_TEX_DEPTH && rtex->is_depth) {
+       if (rscreen->debug_flags & DBG_TEX ||
+           (rtex->resource.b.b.last_level > 0 && rscreen->debug_flags & DBG_TEXMIP)) {
                printf("Texture: npix_x=%u, npix_y=%u, npix_z=%u, blk_w=%u, "
                       "blk_h=%u, blk_d=%u, array_size=%u, last_level=%u, "
-                      "bpe=%u, nsamples=%u, flags=%u\n",
+                      "bpe=%u, nsamples=%u, flags=0x%x, %s\n",
                       rtex->surface.npix_x, rtex->surface.npix_y,
                       rtex->surface.npix_z, rtex->surface.blk_w,
                       rtex->surface.blk_h, rtex->surface.blk_d,
                       rtex->surface.array_size, rtex->surface.last_level,
                       rtex->surface.bpe, rtex->surface.nsamples,
-                      rtex->surface.flags);
-               if (rtex->surface.flags & RADEON_SURF_ZBUFFER) {
-                       for (int i = 0; i <= rtex->surface.last_level; i++) {
-                               printf("  Z %i: offset=%llu, slice_size=%llu, npix_x=%u, "
-                                      "npix_y=%u, npix_z=%u, nblk_x=%u, nblk_y=%u, "
-                                      "nblk_z=%u, pitch_bytes=%u, mode=%u\n",
-                                      i, rtex->surface.level[i].offset,
-                                      rtex->surface.level[i].slice_size,
-                                      u_minify(rtex->resource.b.b.width0, i),
-                                      u_minify(rtex->resource.b.b.height0, i),
-                                      u_minify(rtex->resource.b.b.depth0, i),
-                                      rtex->surface.level[i].nblk_x,
-                                      rtex->surface.level[i].nblk_y,
-                                      rtex->surface.level[i].nblk_z,
-                                      rtex->surface.level[i].pitch_bytes,
-                                      rtex->surface.level[i].mode);
-                       }
+                      rtex->surface.flags, util_format_short_name(base->format));
+               for (int i = 0; i <= rtex->surface.last_level; i++) {
+                       printf("  L %i: offset=%"PRIu64", slice_size=%"PRIu64", npix_x=%u, "
+                              "npix_y=%u, npix_z=%u, nblk_x=%u, nblk_y=%u, "
+                              "nblk_z=%u, pitch_bytes=%u, mode=%u\n",
+                              i, rtex->surface.level[i].offset,
+                              rtex->surface.level[i].slice_size,
+                              u_minify(rtex->resource.b.b.width0, i),
+                              u_minify(rtex->resource.b.b.height0, i),
+                              u_minify(rtex->resource.b.b.depth0, i),
+                              rtex->surface.level[i].nblk_x,
+                              rtex->surface.level[i].nblk_y,
+                              rtex->surface.level[i].nblk_z,
+                              rtex->surface.level[i].pitch_bytes,
+                              rtex->surface.level[i].mode);
                }
                if (rtex->surface.flags & RADEON_SURF_SBUFFER) {
                        for (int i = 0; i <= rtex->surface.last_level; i++) {
-                               printf("  S %i: offset=%llu, slice_size=%llu, npix_x=%u, "
+                               printf("  S %i: offset=%"PRIu64", slice_size=%"PRIu64", npix_x=%u, "
                                       "npix_y=%u, npix_z=%u, nblk_x=%u, nblk_y=%u, "
                                       "nblk_z=%u, pitch_bytes=%u, mode=%u\n",
                                       i, rtex->surface.stencil_level[i].offset,
@@ -675,10 +735,6 @@ static unsigned r600_choose_tiling(struct r600_common_screen *rscreen,
        if (templ->width0 <= 16 || templ->height0 <= 16)
                return RADEON_SURF_MODE_1D;
 
-       /* XXX 2D tiling is currently unimplemented on CIK */
-       if (rscreen->chip_class >= CIK)
-               return RADEON_SURF_MODE_1D;
-
        /* The allocator will switch to 1D if needed. */
        return RADEON_SURF_MODE_2D;
 }
@@ -704,9 +760,9 @@ struct pipe_resource *r600_texture_create(struct pipe_screen *screen,
                                                                  0, NULL, &surface);
 }
 
-struct pipe_resource *r600_texture_from_handle(struct pipe_screen *screen,
-                                              const struct pipe_resource *templ,
-                                              struct winsys_handle *whandle)
+static struct pipe_resource *r600_texture_from_handle(struct pipe_screen *screen,
+                                                     const struct pipe_resource *templ,
+                                                     struct winsys_handle *whandle)
 {
        struct r600_common_screen *rscreen = (struct r600_common_screen*)screen;
        struct pb_buffer *buf = NULL;
@@ -714,6 +770,7 @@ struct pipe_resource *r600_texture_from_handle(struct pipe_screen *screen,
        unsigned array_mode;
        enum radeon_bo_layout micro, macro;
        struct radeon_surface surface;
+       bool scanout;
        int r;
 
        /* Support only 2D textures without mipmaps */
@@ -729,7 +786,7 @@ struct pipe_resource *r600_texture_from_handle(struct pipe_screen *screen,
                                       &surface.bankw, &surface.bankh,
                                       &surface.tile_split,
                                       &surface.stencil_tile_split,
-                                      &surface.mtilea);
+                                      &surface.mtilea, &scanout);
 
        if (macro == RADEON_LAYOUT_TILED)
                array_mode = RADEON_SURF_MODE_2D;
@@ -743,8 +800,7 @@ struct pipe_resource *r600_texture_from_handle(struct pipe_screen *screen,
                return NULL;
        }
 
-       /* always set the scanout flags on SI */
-       if (rscreen->chip_class >= SI)
+       if (scanout)
                surface.flags |= RADEON_SURF_SCANOUT;
 
        return (struct pipe_resource *)r600_texture_create_object(screen, templ,
@@ -771,7 +827,7 @@ bool r600_init_flushed_depth_texture(struct pipe_context *ctx,
        resource.array_size = texture->array_size;
        resource.last_level = texture->last_level;
        resource.nr_samples = texture->nr_samples;
-       resource.usage = staging ? PIPE_USAGE_STAGING : PIPE_USAGE_STATIC;
+       resource.usage = staging ? PIPE_USAGE_STAGING : PIPE_USAGE_DEFAULT;
        resource.bind = texture->bind & ~PIPE_BIND_DEPTH_STENCIL;
        resource.flags = texture->flags | R600_RESOURCE_FLAG_FLUSHED_DEPTH;
 
@@ -805,7 +861,7 @@ static void r600_init_temp_resource_from_box(struct pipe_resource *res,
        res->height0 = box->height;
        res->depth0 = 1;
        res->array_size = 1;
-       res->usage = flags & R600_RESOURCE_FLAG_TRANSFER ? PIPE_USAGE_STAGING : PIPE_USAGE_STATIC;
+       res->usage = flags & R600_RESOURCE_FLAG_TRANSFER ? PIPE_USAGE_STAGING : PIPE_USAGE_DEFAULT;
        res->flags = flags;
 
        /* We must set the correct texture target and dimensions for a 3D box. */
@@ -852,6 +908,12 @@ static void *r600_texture_transfer_map(struct pipe_context *ctx,
        if (rtex->surface.level[level].mode >= RADEON_SURF_MODE_1D)
                use_staging_texture = TRUE;
 
+       /* Untiled buffers in VRAM, which is slow for CPU reads and writes */
+       if (!(usage & PIPE_TRANSFER_MAP_DIRECTLY) &&
+           (rtex->resource.domains == RADEON_DOMAIN_VRAM)) {
+               use_staging_texture = TRUE;
+       }
+
        /* Use a staging texture for uploads if the underlying BO is busy. */
        if (!(usage & PIPE_TRANSFER_READ) &&
            (r600_rings_is_buffer_referenced(rctx, rtex->resource.cs_buf, RADEON_USAGE_READWRITE) ||
@@ -1006,10 +1068,66 @@ static void r600_texture_transfer_unmap(struct pipe_context *ctx,
 
 static const struct u_resource_vtbl r600_texture_vtbl =
 {
-       r600_texture_get_handle,        /* get_handle */
+       NULL,                           /* get_handle */
        r600_texture_destroy,           /* resource_destroy */
        r600_texture_transfer_map,      /* transfer_map */
        NULL,                           /* transfer_flush_region */
        r600_texture_transfer_unmap,    /* transfer_unmap */
        NULL                            /* transfer_inline_write */
 };
+
+struct pipe_surface *r600_create_surface_custom(struct pipe_context *pipe,
+                                               struct pipe_resource *texture,
+                                               const struct pipe_surface *templ,
+                                               unsigned width, unsigned height)
+{
+       struct r600_surface *surface = CALLOC_STRUCT(r600_surface);
+
+       if (surface == NULL)
+               return NULL;
+
+       assert(templ->u.tex.first_layer <= util_max_layer(texture, templ->u.tex.level));
+       assert(templ->u.tex.last_layer <= util_max_layer(texture, templ->u.tex.level));
+
+       pipe_reference_init(&surface->base.reference, 1);
+       pipe_resource_reference(&surface->base.texture, texture);
+       surface->base.context = pipe;
+       surface->base.format = templ->format;
+       surface->base.width = width;
+       surface->base.height = height;
+       surface->base.u = templ->u;
+       return &surface->base;
+}
+
+static struct pipe_surface *r600_create_surface(struct pipe_context *pipe,
+                                               struct pipe_resource *tex,
+                                               const struct pipe_surface *templ)
+{
+       unsigned level = templ->u.tex.level;
+
+       return r600_create_surface_custom(pipe, tex, templ,
+                                         u_minify(tex->width0, level),
+                                         u_minify(tex->height0, level));
+}
+
+static void r600_surface_destroy(struct pipe_context *pipe,
+                                struct pipe_surface *surface)
+{
+       struct r600_surface *surf = (struct r600_surface*)surface;
+       pipe_resource_reference((struct pipe_resource**)&surf->cb_buffer_fmask, NULL);
+       pipe_resource_reference((struct pipe_resource**)&surf->cb_buffer_cmask, NULL);
+       pipe_resource_reference(&surface->texture, NULL);
+       FREE(surface);
+}
+
+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;
+}
+
+void r600_init_context_texture_functions(struct r600_common_context *rctx)
+{
+       rctx->b.create_surface = r600_create_surface;
+       rctx->b.surface_destroy = r600_surface_destroy;
+}