X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fdrivers%2Fvirgl%2Fvirgl_texture.c;h=19ae6ff1d3aeafe7c3db192499eb8bf31f19ce33;hb=b4da53b0c342eaa0dee522e3a3859a93cb77aa84;hp=5a7ce71cb18ccc0419883f8ff8785e63a2ae35f9;hpb=0bc8683ffa10350e98c0be5bd2d740593aeb0966;p=mesa.git diff --git a/src/gallium/drivers/virgl/virgl_texture.c b/src/gallium/drivers/virgl/virgl_texture.c index 5a7ce71cb18..19ae6ff1d3a 100644 --- a/src/gallium/drivers/virgl/virgl_texture.c +++ b/src/gallium/drivers/virgl/virgl_texture.c @@ -79,11 +79,12 @@ static unsigned temp_bind(unsigned orig) 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->bind = temp_bind(orig->bind); - res->format = orig->format; + res->format = fmt; res->width0 = box->width; res->height0 = box->height; res->depth0 = 1; @@ -97,6 +98,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: @@ -122,31 +126,34 @@ static void *texture_transfer_map_plain(struct pipe_context *ctx, struct virgl_winsys *vws = virgl_screen(ctx->screen)->vws; struct virgl_resource *vtex = virgl_resource(resource); struct virgl_transfer *trans; + bool flush, readback; trans = virgl_resource_create_transfer(&vctx->transfer_pool, resource, &vtex->metadata, level, usage, box); - trans->resolve_tmp = NULL; + trans->resolve_transfer = NULL; assert(resource->nr_samples <= 1); - if (virgl_res_needs_flush(vctx, trans)) + flush = virgl_res_needs_flush(vctx, trans); + if (flush) ctx->flush(ctx, NULL, 0); - if (virgl_res_needs_readback(vctx, vtex, usage, level)) { + readback = virgl_res_needs_readback(vctx, vtex, usage, level); + if (readback) vws->transfer_get(vws, vtex->hw_res, box, trans->base.stride, trans->l_stride, trans->offset, level); + if (readback || flush) vws->resource_wait(vws, vtex->hw_res); - } - void *ptr = vws->resource_map(vws, vtex->hw_res); - if (!ptr) { + trans->hw_res_map = vws->resource_map(vws, vtex->hw_res); + if (!trans->hw_res_map) { virgl_resource_destroy_transfer(&vctx->transfer_pool, trans); return NULL; } *transfer = &trans->base; - return ptr + trans->offset; + return trans->hw_res_map + trans->offset; } static void *texture_transfer_map_resolve(struct pipe_context *ctx, @@ -156,8 +163,30 @@ static void *texture_transfer_map_resolve(struct pipe_context *ctx, const struct pipe_box *box, struct pipe_transfer **transfer) { + struct virgl_context *vctx = virgl_context(ctx); + struct virgl_resource *vtex = virgl_resource(resource); struct pipe_resource templ, *resolve_tmp; - virgl_init_temp_resource_from_box(&templ, resource, box, level, 0); + struct virgl_transfer *trans; + + trans = virgl_resource_create_transfer(&vctx->transfer_pool, resource, + &vtex->metadata, level, usage, box); + if (!trans) + return NULL; + + enum pipe_format fmt = resource->format; + if (!virgl_has_readback_format(ctx->screen, 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, fmt)); + } + + virgl_init_temp_resource_from_box(&templ, resource, box, level, 0, fmt); resolve_tmp = ctx->screen->resource_create(ctx->screen, &templ); if (!resolve_tmp) @@ -166,24 +195,71 @@ static void *texture_transfer_map_resolve(struct pipe_context *ctx, struct pipe_box dst_box = *box; dst_box.x = dst_box.y = dst_box.z = 0; - virgl_copy_region_with_blit(ctx, resolve_tmp, 0, &dst_box, resource, level, box); - ctx->flush(ctx, NULL, 0); + if (usage & PIPE_TRANSFER_READ) { + virgl_copy_region_with_blit(ctx, resolve_tmp, 0, &dst_box, resource, + level, box); + ctx->flush(ctx, NULL, 0); + } - void *ptr = texture_transfer_map_plain(ctx, resolve_tmp, 0, usage, box, - transfer); - if (!ptr) { - pipe_resource_reference(&resolve_tmp, NULL); - return NULL; + void *ptr = texture_transfer_map_plain(ctx, resolve_tmp, 0, usage, &dst_box, + &trans->resolve_transfer); + if (!ptr) + goto fail; + + *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, + 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, + box->width, box->height, 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 ((usage & PIPE_TRANSFER_WRITE) == 0) + pipe_resource_reference(&trans->resolve_transfer->resource, NULL); + + return ptr + trans->offset; } - virgl_transfer(*transfer)->resolve_tmp = virgl_resource(resolve_tmp); +fail: + pipe_resource_reference(&resolve_tmp, NULL); + virgl_resource_destroy_transfer(&vctx->transfer_pool, trans); + return NULL; +} + +static bool needs_resolve(struct pipe_screen *screen, + struct pipe_resource *resource, unsigned usage) +{ + if (resource->nr_samples > 1) + return true; - struct virgl_resource_metadata *data = &virgl_resource(resolve_tmp)->metadata; - assert((*transfer)->stride == data->stride[0]); - assert((*transfer)->layer_stride == data->layer_stride[0]); - assert(virgl_transfer(*transfer)->offset == 0); + if (usage & PIPE_TRANSFER_READ) + return !util_format_is_depth_or_stencil(resource->format) && + !virgl_has_readback_format(screen, resource->format); - return ptr; + return false; } static void *virgl_texture_transfer_map(struct pipe_context *ctx, @@ -193,33 +269,59 @@ static void *virgl_texture_transfer_map(struct pipe_context *ctx, const struct pipe_box *box, struct pipe_transfer **transfer) { - if (resource->nr_samples > 1) + if (needs_resolve(ctx->screen, resource, usage)) return texture_transfer_map_resolve(ctx, resource, level, usage, box, transfer); return texture_transfer_map_plain(ctx, resource, level, usage, box, transfer); } +static void flush_data(struct pipe_context *ctx, + struct virgl_transfer *trans, + const struct pipe_box *box) +{ + struct virgl_winsys *vws = virgl_screen(ctx->screen)->vws; + vws->transfer_put(vws, virgl_resource(trans->base.resource)->hw_res, box, + trans->base.stride, trans->l_stride, trans->offset, + trans->base.level); +} + 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_resource *vtex = virgl_resource(transfer->resource); bool queue_unmap = false; if (transfer->usage & PIPE_TRANSFER_WRITE && (transfer->usage & PIPE_TRANSFER_FLUSH_EXPLICIT) == 0) { - if (trans->resolve_tmp) { - struct virgl_winsys *vws = virgl_screen(ctx->screen)->vws; - vws->transfer_put(vws, vtex->hw_res, &transfer->box, - trans->base.stride, trans->l_stride, - trans->offset, transfer->level); + + 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; } - pipe_resource_reference((struct pipe_resource **)&trans->resolve_tmp, NULL); + if (trans->resolve_transfer) { + pipe_resource_reference(&trans->resolve_transfer->resource, NULL); + virgl_resource_destroy_transfer(&vctx->transfer_pool, + virgl_transfer(trans->resolve_transfer)); + } if (queue_unmap) virgl_transfer_queue_unmap(&vctx->queue, trans);