X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fdrivers%2Fvirgl%2Fvirgl_texture.c;h=1b39c6382dc05a738c2cd8174946e09317c77acd;hb=eb3047c094abfa03e071453d7c373e9c2c574370;hp=4d08da548cb34cdd686c080939a4753335fa7748;hpb=a63da9c062bd925482250cd0939aa377f53730a2;p=mesa.git diff --git a/src/gallium/drivers/virgl/virgl_texture.c b/src/gallium/drivers/virgl/virgl_texture.c index 4d08da548cb..1b39c6382dc 100644 --- a/src/gallium/drivers/virgl/virgl_texture.c +++ b/src/gallium/drivers/virgl/virgl_texture.c @@ -25,13 +25,14 @@ #include "util/u_memory.h" #include "virgl_context.h" +#include "virgl_encode.h" #include "virgl_resource.h" #include "virgl_screen.h" static void virgl_copy_region_with_blit(struct pipe_context *pipe, struct pipe_resource *dst, unsigned dst_level, - unsigned dstx, unsigned dsty, unsigned dstz, + const struct pipe_box *dst_box, struct pipe_resource *src, unsigned src_level, const struct pipe_box *src_box) @@ -46,12 +47,12 @@ static void virgl_copy_region_with_blit(struct pipe_context *pipe, blit.dst.resource = dst; blit.dst.format = dst->format; blit.dst.level = dst_level; - blit.dst.box.x = dstx; - blit.dst.box.y = dsty; - blit.dst.box.z = dstz; - blit.dst.box.width = src_box->width; - blit.dst.box.height = src_box->height; - blit.dst.box.depth = src_box->depth; + blit.dst.box.x = dst_box->x; + blit.dst.box.y = dst_box->y; + blit.dst.box.z = dst_box->z; + blit.dst.box.width = dst_box->width; + blit.dst.box.height = dst_box->height; + blit.dst.box.depth = dst_box->depth; blit.mask = util_format_get_mask(src->format) & util_format_get_mask(dst->format); blit.filter = PIPE_TEX_FILTER_NEAREST; @@ -60,13 +61,27 @@ static void virgl_copy_region_with_blit(struct pipe_context *pipe, pipe->blit(pipe, &blit); } } + +static unsigned temp_bind(unsigned orig) +{ + unsigned warn = ~(PIPE_BIND_RENDER_TARGET | PIPE_BIND_DEPTH_STENCIL | + PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_DISPLAY_TARGET); + if (orig & warn) + debug_printf("VIRGL: Warning, possibly unhandled bind: %x\n", + orig & warn); + + return orig & (PIPE_BIND_DEPTH_STENCIL | PIPE_BIND_RENDER_TARGET); +} + static void virgl_init_temp_resource_from_box(struct pipe_resource *res, struct pipe_resource *orig, const struct pipe_box *box, - unsigned level, unsigned flags) + unsigned level, unsigned flags, + enum pipe_format fmt) { memset(res, 0, sizeof(*res)); - res->format = orig->format; + res->bind = temp_bind(orig->bind); + res->format = fmt; res->width0 = box->width; res->height0 = box->height; res->depth0 = 1; @@ -80,6 +95,9 @@ static void virgl_init_temp_resource_from_box(struct pipe_resource *res, else res->target = PIPE_TEXTURE_2D; + if (res->target != PIPE_BUFFER) + res->bind = PIPE_BIND_RENDER_TARGET; + switch (res->target) { case PIPE_TEXTURE_1D_ARRAY: case PIPE_TEXTURE_2D_ARRAY: @@ -94,255 +112,206 @@ static void virgl_init_temp_resource_from_box(struct pipe_resource *res, } } -static unsigned -vrend_get_tex_image_offset(const struct virgl_texture *res, - unsigned level, unsigned layer) -{ - const struct pipe_resource *pres = &res->base.u.b; - const unsigned hgt = u_minify(pres->height0, level); - const unsigned nblocksy = util_format_get_nblocksy(pres->format, hgt); - unsigned offset = res->metadata.level_offset[level]; - - if (pres->target == PIPE_TEXTURE_CUBE || - pres->target == PIPE_TEXTURE_CUBE_ARRAY || - pres->target == PIPE_TEXTURE_3D || - pres->target == PIPE_TEXTURE_2D_ARRAY) { - offset += layer * nblocksy * res->metadata.stride[level]; - } - else if (pres->target == PIPE_TEXTURE_1D_ARRAY) { - offset += layer * res->metadata.stride[level]; - } - else { - assert(layer == 0); - } - - return offset; -} - -static void *virgl_texture_transfer_map(struct pipe_context *ctx, - struct pipe_resource *resource, - unsigned level, - unsigned usage, - const struct pipe_box *box, - struct pipe_transfer **transfer) +static void *texture_transfer_map_resolve(struct pipe_context *ctx, + struct pipe_resource *resource, + unsigned level, + unsigned usage, + const struct pipe_box *box, + struct pipe_transfer **transfer) { struct virgl_context *vctx = virgl_context(ctx); - struct virgl_screen *vs = virgl_screen(ctx->screen); - struct virgl_texture *vtex = virgl_texture(resource); - enum pipe_format format = resource->format; + struct virgl_resource *vtex = virgl_resource(resource); + struct pipe_resource templ, *resolve_tmp; struct virgl_transfer *trans; - void *ptr; - boolean readback = TRUE; - uint32_t offset; - struct virgl_hw_res *hw_res; - const unsigned h = u_minify(vtex->base.u.b.height0, level); - const unsigned nblocksy = util_format_get_nblocksy(format, h); - uint32_t l_stride; - bool doflushwait; - - doflushwait = virgl_res_needs_flush_wait(vctx, &vtex->base, usage); - if (doflushwait) - ctx->flush(ctx, NULL, 0); - trans = slab_alloc(&vctx->transfer_pool); + trans = virgl_resource_create_transfer(vctx, resource, + &vtex->metadata, level, usage, box); if (!trans) return NULL; - trans->base.resource = resource; - trans->base.level = level; - trans->base.usage = usage; - trans->base.box = *box; - trans->base.stride = vtex->metadata.stride[level]; - trans->base.layer_stride = trans->base.stride * nblocksy; - - if (resource->target != PIPE_TEXTURE_3D && - resource->target != PIPE_TEXTURE_CUBE && - resource->target != PIPE_TEXTURE_1D_ARRAY && - resource->target != PIPE_TEXTURE_2D_ARRAY && - resource->target != PIPE_TEXTURE_CUBE_ARRAY) - l_stride = 0; - else - l_stride = trans->base.layer_stride; - - if (resource->nr_samples > 1) { - struct pipe_resource tmp_resource; - virgl_init_temp_resource_from_box(&tmp_resource, resource, box, - level, 0); - - trans->resolve_tmp = (struct virgl_resource *)ctx->screen->resource_create(ctx->screen, &tmp_resource); - - virgl_copy_region_with_blit(ctx, &trans->resolve_tmp->u.b, 0, 0, 0, 0, resource, level, box); - ctx->flush(ctx, NULL, 0); - /* we want to do a resolve blit into the temporary */ - hw_res = trans->resolve_tmp->hw_res; - offset = 0; - trans->base.stride = ((struct virgl_texture*)trans->resolve_tmp)->metadata.stride[level]; - trans->base.layer_stride = trans->base.stride * nblocksy; - } else { - offset = vrend_get_tex_image_offset(vtex, level, box->z); - - offset += box->y / util_format_get_blockheight(format) * trans->base.stride + - box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format); - hw_res = vtex->base.hw_res; - trans->resolve_tmp = NULL; + enum pipe_format fmt = resource->format; + if (!virgl_has_readback_format(ctx->screen, pipe_to_virgl_format(fmt))) { + if (util_format_fits_8unorm(util_format_description(fmt))) + fmt = PIPE_FORMAT_R8G8B8A8_UNORM; + else if (util_format_is_pure_sint(fmt)) + fmt = PIPE_FORMAT_R32G32B32A32_SINT; + else if (util_format_is_pure_uint(fmt)) + fmt = PIPE_FORMAT_R32G32B32A32_UINT; + else + fmt = PIPE_FORMAT_R32G32B32A32_FLOAT; + assert(virgl_has_readback_format(ctx->screen, pipe_to_virgl_format(fmt))); } - readback = virgl_res_needs_readback(vctx, &vtex->base, usage); - if (readback) - vs->vws->transfer_get(vs->vws, hw_res, box, trans->base.stride, l_stride, offset, level); + struct pipe_box dst_box = *box; + dst_box.x = dst_box.y = dst_box.z = 0; + if (usage & PIPE_TRANSFER_READ) { + /* readback should scale to the block size */ + dst_box.width = align(dst_box.width, + util_format_get_blockwidth(resource->format)); + dst_box.height = align(dst_box.height, + util_format_get_blockheight(resource->format)); + } - if (doflushwait || readback) - vs->vws->resource_wait(vs->vws, vtex->base.hw_res); + virgl_init_temp_resource_from_box(&templ, resource, &dst_box, level, 0, fmt); - ptr = vs->vws->resource_map(vs->vws, hw_res); - if (!ptr) { - slab_free(&vctx->transfer_pool, trans); + resolve_tmp = ctx->screen->resource_create(ctx->screen, &templ); + if (!resolve_tmp) return NULL; + + if (usage & PIPE_TRANSFER_READ) { + virgl_copy_region_with_blit(ctx, resolve_tmp, 0, &dst_box, resource, + level, box); + ctx->flush(ctx, NULL, 0); } - trans->offset = offset; - *transfer = &trans->base; + void *ptr = virgl_resource_transfer_map(ctx, resolve_tmp, 0, usage, &dst_box, + &trans->resolve_transfer); + if (!ptr) + goto fail; - return ptr + trans->offset; -} + /* trans->resolve_transfer owns resolve_tmp now */ + pipe_resource_reference(&resolve_tmp, NULL); -static void virgl_texture_transfer_unmap(struct pipe_context *ctx, - struct pipe_transfer *transfer) -{ - struct virgl_context *vctx = virgl_context(ctx); - struct virgl_transfer *trans = virgl_transfer(transfer); - struct virgl_texture *vtex = virgl_texture(transfer->resource); - uint32_t l_stride; - - if (transfer->resource->target != PIPE_TEXTURE_3D && - transfer->resource->target != PIPE_TEXTURE_CUBE && - transfer->resource->target != PIPE_TEXTURE_1D_ARRAY && - transfer->resource->target != PIPE_TEXTURE_2D_ARRAY && - transfer->resource->target != PIPE_TEXTURE_CUBE_ARRAY) - l_stride = 0; - else - l_stride = trans->base.layer_stride; + *transfer = &trans->base; + if (fmt == resource->format) { + trans->base.stride = trans->resolve_transfer->stride; + trans->base.layer_stride = trans->resolve_transfer->layer_stride; + return ptr; + } else { + if (usage & PIPE_TRANSFER_READ) { + struct virgl_winsys *vws = virgl_screen(ctx->screen)->vws; + void *src = ptr; + ptr = vws->resource_map(vws, vtex->hw_res); + if (!ptr) + goto fail; + + if (!util_format_translate_3d(resource->format, + ptr + vtex->metadata.level_offset[level], + trans->base.stride, + trans->base.layer_stride, + box->x, box->y, box->z, + fmt, + src, + trans->resolve_transfer->stride, + trans->resolve_transfer->layer_stride, + 0, 0, 0, + dst_box.width, + dst_box.height, + dst_box.depth)) { + debug_printf("failed to translate format %s to %s\n", + util_format_short_name(fmt), + util_format_short_name(resource->format)); + goto fail; + } + } - if (trans->base.usage & PIPE_TRANSFER_WRITE) { - if (!(transfer->usage & PIPE_TRANSFER_FLUSH_EXPLICIT)) { - struct virgl_screen *vs = virgl_screen(ctx->screen); - vtex->base.clean = FALSE; - vctx->num_transfers++; - vs->vws->transfer_put(vs->vws, vtex->base.hw_res, - &transfer->box, trans->base.stride, l_stride, trans->offset, transfer->level); + if ((usage & PIPE_TRANSFER_WRITE) == 0) + pipe_resource_reference(&trans->resolve_transfer->resource, NULL); - } + return ptr + trans->offset; } - if (trans->resolve_tmp) - pipe_resource_reference((struct pipe_resource **)&trans->resolve_tmp, NULL); - - slab_free(&vctx->transfer_pool, trans); +fail: + pipe_resource_reference(&resolve_tmp, NULL); + virgl_resource_destroy_transfer(vctx, trans); + return NULL; } - -static void -vrend_resource_layout(struct virgl_texture *res, - uint32_t *total_size) +static bool needs_resolve(struct pipe_screen *screen, + struct pipe_resource *resource, unsigned usage) { - struct pipe_resource *pt = &res->base.u.b; - unsigned level; - unsigned width = pt->width0; - unsigned height = pt->height0; - unsigned depth = pt->depth0; - unsigned buffer_size = 0; - - for (level = 0; level <= pt->last_level; level++) { - unsigned slices; - - if (pt->target == PIPE_TEXTURE_CUBE) - slices = 6; - else if (pt->target == PIPE_TEXTURE_3D) - slices = depth; - else - slices = pt->array_size; + if (resource->nr_samples > 1) + return true; - res->metadata.stride[level] = util_format_get_stride(pt->format, width); - res->metadata.level_offset[level] = buffer_size; + if (usage & PIPE_TRANSFER_READ) + return !util_format_is_depth_or_stencil(resource->format) && + !virgl_has_readback_format(screen, pipe_to_virgl_format(resource->format)); - buffer_size += (util_format_get_nblocksy(pt->format, height) * - slices * res->metadata.stride[level]); + return false; +} - width = u_minify(width, 1); - height = u_minify(height, 1); - depth = u_minify(depth, 1); - } +static void *virgl_texture_transfer_map(struct pipe_context *ctx, + struct pipe_resource *resource, + unsigned level, + unsigned usage, + const struct pipe_box *box, + struct pipe_transfer **transfer) +{ + if (needs_resolve(ctx->screen, resource, usage)) + return texture_transfer_map_resolve(ctx, resource, level, usage, box, + transfer); - if (pt->nr_samples <= 1) - *total_size = buffer_size; - else /* don't create guest backing store for MSAA */ - *total_size = 0; + return virgl_resource_transfer_map(ctx, resource, level, usage, box, transfer); } -static boolean virgl_texture_get_handle(struct pipe_screen *screen, - struct pipe_resource *ptex, - struct winsys_handle *whandle) +static void flush_data(struct pipe_context *ctx, + struct virgl_transfer *trans, + const struct pipe_box *box) { - struct virgl_screen *vs = virgl_screen(screen); - struct virgl_texture *vtex = virgl_texture(ptex); - - return vs->vws->resource_get_handle(vs->vws, vtex->base.hw_res, - vtex->metadata.stride[0], whandle); + struct virgl_winsys *vws = virgl_screen(ctx->screen)->vws; + vws->transfer_put(vws, trans->hw_res, box, + trans->base.stride, trans->l_stride, trans->offset, + trans->base.level); } -static void virgl_texture_destroy(struct pipe_screen *screen, - struct pipe_resource *res) +static void virgl_texture_transfer_unmap(struct pipe_context *ctx, + struct pipe_transfer *transfer) { - struct virgl_screen *vs = virgl_screen(screen); - struct virgl_texture *vtex = virgl_texture(res); - vs->vws->resource_unref(vs->vws, vtex->base.hw_res); - FREE(vtex); + struct virgl_context *vctx = virgl_context(ctx); + struct virgl_transfer *trans = virgl_transfer(transfer); + bool queue_unmap = false; + + if (transfer->usage & PIPE_TRANSFER_WRITE && + (transfer->usage & PIPE_TRANSFER_FLUSH_EXPLICIT) == 0) { + + if (trans->resolve_transfer && (trans->base.resource->format == + trans->resolve_transfer->resource->format)) { + flush_data(ctx, virgl_transfer(trans->resolve_transfer), + &trans->resolve_transfer->box); + + /* FINISHME: In case the destination format isn't renderable here, the + * blit here will currently fail. This could for instance happen if the + * mapped resource is of a compressed format, and it's mapped with both + * read and write usage. + */ + + virgl_copy_region_with_blit(ctx, + trans->base.resource, trans->base.level, + &transfer->box, + trans->resolve_transfer->resource, 0, + &trans->resolve_transfer->box); + ctx->flush(ctx, NULL, 0); + } else + queue_unmap = true; + } + + if (trans->resolve_transfer) { + virgl_resource_destroy_transfer(vctx, + virgl_transfer(trans->resolve_transfer)); + } + + if (queue_unmap) { + if (trans->copy_src_hw_res) { + virgl_encode_copy_transfer(vctx, trans); + virgl_resource_destroy_transfer(vctx, trans); + } else { + virgl_transfer_queue_unmap(&vctx->queue, trans); + } + } else { + virgl_resource_destroy_transfer(vctx, trans); + } } static const struct u_resource_vtbl virgl_texture_vtbl = { - virgl_texture_get_handle, /* get_handle */ - virgl_texture_destroy, /* resource_destroy */ + virgl_resource_get_handle, /* get_handle */ + virgl_resource_destroy, /* resource_destroy */ virgl_texture_transfer_map, /* transfer_map */ NULL, /* transfer_flush_region */ virgl_texture_transfer_unmap, /* transfer_unmap */ }; -struct pipe_resource * -virgl_texture_from_handle(struct virgl_screen *vs, - const struct pipe_resource *template, - struct winsys_handle *whandle) +void virgl_texture_init(struct virgl_resource *res) { - struct virgl_texture *tex = CALLOC_STRUCT(virgl_texture); - tex->base.u.b = *template; - tex->base.u.b.screen = &vs->base; - pipe_reference_init(&tex->base.u.b.reference, 1); - tex->base.u.vtbl = &virgl_texture_vtbl; - - tex->base.hw_res = vs->vws->resource_create_from_handle(vs->vws, whandle); - return &tex->base.u.b; -} - -struct pipe_resource *virgl_texture_create(struct virgl_screen *vs, - const struct pipe_resource *template) -{ - struct virgl_texture *tex; - uint32_t size; - unsigned vbind; - - tex = CALLOC_STRUCT(virgl_texture); - tex->base.clean = TRUE; - tex->base.u.b = *template; - tex->base.u.b.screen = &vs->base; - pipe_reference_init(&tex->base.u.b.reference, 1); - tex->base.u.vtbl = &virgl_texture_vtbl; - vrend_resource_layout(tex, &size); - - vbind = pipe_to_virgl_bind(template->bind); - tex->base.hw_res = vs->vws->resource_create(vs->vws, template->target, template->format, vbind, template->width0, template->height0, template->depth0, template->array_size, template->last_level, template->nr_samples, size); - if (!tex->base.hw_res) { - FREE(tex); - return NULL; - } - return &tex->base.u.b; + res->u.vtbl = &virgl_texture_vtbl; }