#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,
}
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;
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);
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);
}
cl_width = 64;
cl_height = 32;
break;
+ case 16: /* Hawaii */
+ cl_width = 64;
+ cl_height = 64;
+ break;
default:
assert(0);
return;
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 */
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,
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)
/* 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;
}
}
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,
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;
}
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;
unsigned array_mode;
enum radeon_bo_layout micro, macro;
struct radeon_surface surface;
+ bool scanout;
int r;
/* Support only 2D textures without mipmaps */
&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;
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,
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;
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. */
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) ||
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;
+}