X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fdrivers%2Ffreedreno%2Ffreedreno_resource.c;h=69e545268481177c8d848b51d2c998a819a3e9be;hb=e92bc6b38e90339a394e95a562bcce35c3ee9696;hp=3982ecd0f9002a0bff2305eb193126968ac54105;hpb=cb9e07aa84ff2dd8492fd8a7064ff2539d7d40f9;p=mesa.git diff --git a/src/gallium/drivers/freedreno/freedreno_resource.c b/src/gallium/drivers/freedreno/freedreno_resource.c index 3982ecd0f90..69e54526848 100644 --- a/src/gallium/drivers/freedreno/freedreno_resource.c +++ b/src/gallium/drivers/freedreno/freedreno_resource.c @@ -36,8 +36,30 @@ #include "freedreno_screen.h" #include "freedreno_surface.h" #include "freedreno_context.h" +#include "freedreno_query_hw.h" #include "freedreno_util.h" +#include + +static void +realloc_bo(struct fd_resource *rsc, uint32_t size) +{ + struct fd_screen *screen = fd_screen(rsc->base.b.screen); + uint32_t flags = DRM_FREEDRENO_GEM_CACHE_WCOMBINE | + DRM_FREEDRENO_GEM_TYPE_KMEM; /* TODO */ + + /* if we start using things other than write-combine, + * be sure to check for PIPE_RESOURCE_FLAG_MAP_COHERENT + */ + + if (rsc->bo) + fd_bo_del(rsc->bo); + + rsc->bo = fd_bo_new(screen->dev, size, flags); + rsc->timestamp = 0; + rsc->dirty = false; +} + static void fd_resource_transfer_flush_region(struct pipe_context *pctx, struct pipe_transfer *ptrans, const struct pipe_box *box) @@ -79,7 +101,11 @@ fd_resource_transfer_map(struct pipe_context *pctx, struct pipe_transfer *ptrans; enum pipe_format format = prsc->format; uint32_t op = 0; + uint32_t offset; char *buf; + int ret = 0; + + DBG("prsc=%p, level=%u, usage=%x", prsc, level, usage); ptrans = util_slab_alloc(&ctx->transfer_pool); if (!ptrans) @@ -93,33 +119,51 @@ fd_resource_transfer_map(struct pipe_context *pctx, ptrans->usage = usage; ptrans->box = *box; ptrans->stride = slice->pitch * rsc->cpp; - ptrans->layer_stride = ptrans->stride; + ptrans->layer_stride = slice->size0; + + if (usage & PIPE_TRANSFER_READ) + op |= DRM_FREEDRENO_PREP_READ; + + if (usage & PIPE_TRANSFER_WRITE) + op |= DRM_FREEDRENO_PREP_WRITE; /* some state trackers (at least XA) don't do this.. */ - if (!(usage & PIPE_TRANSFER_FLUSH_EXPLICIT)) + if (!(usage & (PIPE_TRANSFER_FLUSH_EXPLICIT | PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE))) fd_resource_transfer_flush_region(pctx, ptrans, box); + if (usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) { + realloc_bo(rsc, fd_bo_size(rsc->bo)); + } else if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) { + ret = fd_bo_cpu_prep(rsc->bo, ctx->screen->pipe, op); + if (ret) + goto fail; + } + buf = fd_bo_map(rsc->bo); if (!buf) { fd_resource_transfer_unmap(pctx, ptrans); return NULL; } - if (usage & PIPE_TRANSFER_READ) - op |= DRM_FREEDRENO_PREP_READ; - - if (usage & PIPE_TRANSFER_WRITE) - op |= DRM_FREEDRENO_PREP_WRITE; + *pptrans = ptrans; - if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) - fd_bo_cpu_prep(rsc->bo, ctx->screen->pipe, op); + if (rsc->layer_first) { + offset = slice->offset + + box->y / util_format_get_blockheight(format) * ptrans->stride + + box->x / util_format_get_blockwidth(format) * rsc->cpp + + box->z * rsc->layer_size; + } else { + offset = slice->offset + + box->y / util_format_get_blockheight(format) * ptrans->stride + + box->x / util_format_get_blockwidth(format) * rsc->cpp + + box->z * slice->size0; + } - *pptrans = ptrans; + return buf + offset; - return buf + slice->offset + - box->y / util_format_get_blockheight(format) * ptrans->stride + - box->x / util_format_get_blockwidth(format) * rsc->cpp + - box->z * slice->size0; +fail: + fd_resource_transfer_unmap(pctx, ptrans); + return NULL; } static void @@ -127,7 +171,8 @@ fd_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *prsc) { struct fd_resource *rsc = fd_resource(prsc); - fd_bo_del(rsc->bo); + if (rsc->bo) + fd_bo_del(rsc->bo); FREE(rsc); } @@ -153,23 +198,33 @@ static const struct u_resource_vtbl fd_resource_vtbl = { }; static uint32_t -setup_slices(struct fd_resource *rsc) +setup_slices(struct fd_resource *rsc, uint32_t alignment) { struct pipe_resource *prsc = &rsc->base.b; uint32_t level, size = 0; uint32_t width = prsc->width0; uint32_t height = prsc->height0; uint32_t depth = prsc->depth0; + /* in layer_first layout, the level (slice) contains just one + * layer (since in fact the layer contains the slices) + */ + uint32_t layers_in_level = rsc->layer_first ? 1 : prsc->array_size; for (level = 0; level <= prsc->last_level; level++) { struct fd_resource_slice *slice = fd_resource_slice(rsc, level); - uint32_t aligned_width = align(width, 32); - slice->pitch = aligned_width; + slice->pitch = width = align(width, 32); slice->offset = size; - slice->size0 = slice->pitch * height * rsc->cpp; + /* 1d array, 2d array, 3d textures (but not cube!) must all have the + * same layer size for each miplevel on a3xx. These are also the + * targets that have non-1 alignment. + */ + if (level == 0 || layers_in_level == 1 || alignment == 1) + slice->size0 = align(slice->pitch * height * rsc->cpp, alignment); + else + slice->size0 = rsc->slices[0].size0; - size += slice->size0 * depth * prsc->array_size; + size += slice->size0 * depth * layers_in_level; width = u_minify(width, 1); height = u_minify(height, 1); @@ -179,6 +234,22 @@ setup_slices(struct fd_resource *rsc) return size; } +static uint32_t +slice_alignment(struct pipe_screen *pscreen, const struct pipe_resource *tmpl) +{ + /* on a3xx, 2d array and 3d textures seem to want their + * layers aligned to page boundaries: + */ + switch (tmpl->target) { + case PIPE_TEXTURE_3D: + case PIPE_TEXTURE_1D_ARRAY: + case PIPE_TEXTURE_2D_ARRAY: + return 4096; + default: + return 1; + } +} + /** * Create a new texture object, using the given template info. */ @@ -186,10 +257,9 @@ static struct pipe_resource * fd_resource_create(struct pipe_screen *pscreen, const struct pipe_resource *tmpl) { - struct fd_screen *screen = fd_screen(pscreen); struct fd_resource *rsc = CALLOC_STRUCT(fd_resource); struct pipe_resource *prsc = &rsc->base.b; - uint32_t flags, size; + uint32_t size; DBG("target=%d, format=%s, %ux%ux%u, array_size=%u, last_level=%u, " "nr_samples=%u, usage=%u, bind=%x, flags=%x", @@ -211,14 +281,33 @@ fd_resource_create(struct pipe_screen *pscreen, assert(rsc->cpp); - size = setup_slices(rsc); + if (is_a4xx(fd_screen(pscreen))) { + switch (tmpl->target) { + case PIPE_TEXTURE_3D: + /* TODO 3D_ARRAY? */ + rsc->layer_first = false; + break; + default: + rsc->layer_first = true; + break; + } + } - flags = DRM_FREEDRENO_GEM_CACHE_WCOMBINE | - DRM_FREEDRENO_GEM_TYPE_KMEM; /* TODO */ + size = setup_slices(rsc, slice_alignment(pscreen, tmpl)); - rsc->bo = fd_bo_new(screen->dev, size, flags); + if (rsc->layer_first) { + rsc->layer_size = align(size, 4096); + size = rsc->layer_size * prsc->array_size; + } + + realloc_bo(rsc, size); + if (!rsc->bo) + goto fail; return prsc; +fail: + fd_resource_destroy(pscreen, prsc); + return NULL; } /** @@ -251,6 +340,8 @@ fd_resource_from_handle(struct pipe_screen *pscreen, prsc->screen = pscreen; rsc->bo = fd_screen_bo_from_handle(pscreen, handle, &slice->pitch); + if (!rsc->bo) + goto fail; rsc->base.vtbl = &fd_resource_vtbl; rsc->cpp = util_format_get_blocksize(tmpl->format); @@ -259,9 +350,42 @@ fd_resource_from_handle(struct pipe_screen *pscreen, assert(rsc->cpp); return prsc; + +fail: + fd_resource_destroy(pscreen, prsc); + return NULL; } -static bool render_blit(struct pipe_context *pctx, struct pipe_blit_info *info); +static void fd_blitter_pipe_begin(struct fd_context *ctx); +static void fd_blitter_pipe_end(struct fd_context *ctx); + +/** + * _copy_region using pipe (3d engine) + */ +static bool +fd_blitter_pipe_copy_region(struct fd_context *ctx, + struct pipe_resource *dst, + unsigned dst_level, + unsigned dstx, unsigned dsty, unsigned dstz, + struct pipe_resource *src, + unsigned src_level, + const struct pipe_box *src_box) +{ + /* not until we allow rendertargets to be buffers */ + if (dst->target == PIPE_BUFFER || src->target == PIPE_BUFFER) + return false; + + if (!util_blitter_is_copy_supported(ctx->blitter, dst, src)) + return false; + + fd_blitter_pipe_begin(ctx); + util_blitter_copy_texture(ctx->blitter, + dst, dst_level, dstx, dsty, dstz, + src, src_level, src_box); + fd_blitter_pipe_end(ctx); + + return true; +} /** * Copy a block of pixels from one resource to another. @@ -277,40 +401,33 @@ fd_resource_copy_region(struct pipe_context *pctx, unsigned src_level, const struct pipe_box *src_box) { + struct fd_context *ctx = fd_context(pctx); + /* TODO if we have 2d core, or other DMA engine that could be used * for simple copies and reasonably easily synchronized with the 3d * core, this is where we'd plug it in.. */ - struct pipe_blit_info info = { - .dst = { - .resource = dst, - .box = { - .x = dstx, - .y = dsty, - .z = dstz, - .width = src_box->width, - .height = src_box->height, - .depth = src_box->depth, - }, - .format = util_format_linear(dst->format), - }, - .src = { - .resource = src, - .box = *src_box, - .format = util_format_linear(src->format), - }, - .mask = PIPE_MASK_RGBA, - .filter = PIPE_TEX_FILTER_NEAREST, - }; - render_blit(pctx, &info); + + /* try blit on 3d pipe: */ + if (fd_blitter_pipe_copy_region(ctx, + dst, dst_level, dstx, dsty, dstz, + src, src_level, src_box)) + return; + + /* else fallback to pure sw: */ + util_resource_copy_region(pctx, + dst, dst_level, dstx, dsty, dstz, + src, src_level, src_box); } -/* Optimal hardware path for blitting pixels. +/** + * Optimal hardware path for blitting pixels. * Scaling, format conversion, up- and downsampling (resolve) are allowed. */ static void fd_blit(struct pipe_context *pctx, const struct pipe_blit_info *blit_info) { + struct fd_context *ctx = fd_context(pctx); struct pipe_blit_info info = *blit_info; if (info.src.resource->nr_samples > 1 && @@ -330,23 +447,23 @@ fd_blit(struct pipe_context *pctx, const struct pipe_blit_info *blit_info) info.mask &= ~PIPE_MASK_S; } - render_blit(pctx, &info); -} - -static bool -render_blit(struct pipe_context *pctx, struct pipe_blit_info *info) -{ - struct fd_context *ctx = fd_context(pctx); - - if (!util_blitter_is_blit_supported(ctx->blitter, info)) { + if (!util_blitter_is_blit_supported(ctx->blitter, &info)) { DBG("blit unsupported %s -> %s", - util_format_short_name(info->src.resource->format), - util_format_short_name(info->dst.resource->format)); - return false; + util_format_short_name(info.src.resource->format), + util_format_short_name(info.dst.resource->format)); + return; } - util_blitter_save_vertex_buffer_slot(ctx->blitter, ctx->vertexbuf.vb); - util_blitter_save_vertex_elements(ctx->blitter, ctx->vtx); + fd_blitter_pipe_begin(ctx); + util_blitter_blit(ctx->blitter, &info); + fd_blitter_pipe_end(ctx); +} + +static void +fd_blitter_pipe_begin(struct fd_context *ctx) +{ + util_blitter_save_vertex_buffer_slot(ctx->blitter, ctx->vtx.vertexbuf.vb); + util_blitter_save_vertex_elements(ctx->blitter, ctx->vtx.vtx); util_blitter_save_vertex_shader(ctx->blitter, ctx->prog.vp); util_blitter_save_rasterizer(ctx->blitter, ctx->rasterizer); util_blitter_save_viewport(ctx->blitter, &ctx->viewport); @@ -363,9 +480,22 @@ render_blit(struct pipe_context *pctx, struct pipe_blit_info *info) util_blitter_save_fragment_sampler_views(ctx->blitter, ctx->fragtex.num_textures, ctx->fragtex.textures); - util_blitter_blit(ctx->blitter, info); + fd_hw_query_set_stage(ctx, ctx->ring, FD_STAGE_BLIT); +} + +static void +fd_blitter_pipe_end(struct fd_context *ctx) +{ + fd_hw_query_set_stage(ctx, ctx->ring, FD_STAGE_NULL); +} - return true; +static void +fd_flush_resource(struct pipe_context *pctx, struct pipe_resource *prsc) +{ + struct fd_resource *rsc = fd_resource(prsc); + + if (rsc->dirty) + fd_context_render(pctx); } void @@ -388,4 +518,5 @@ fd_resource_context_init(struct pipe_context *pctx) pctx->surface_destroy = fd_surface_destroy; pctx->resource_copy_region = fd_resource_copy_region; pctx->blit = fd_blit; + pctx->flush_resource = fd_flush_resource; }